Skip to main content
API reference

Orgs

Generated HTTP reference for the 15 operations the published OpenAPI document describes under orgs.

16 min read
View MarkdownEdit on GitHub

Orgs

This page is generated from the published OpenAPI document. It is complete with respect to that document and says nothing about surfaces the document does not describe yet. See what is generated here for what that means.

Base URL: https://api.codespar.dev

Every operation below requires a Bearer token. See Authentication.

POST /v1/orgs/{orgId}/agents

Register an agent identity and mint its first signing key

Path parameters

NameTypeRequiredDescription
orgIdstringyes

Request body

FieldTypeRequiredDescription
agent_idstringyes
display_namestringno
principal_refstringyes

Responses

StatusBodyDescription
201objectOK
400objectThe body failed the schema (details.issues carries the Zod issues), or the org or the handle contains characters a did:web cannot hold.
403objectThe \{orgId\} in the path is not the authenticated org.
409objectThe agent already has an active key, or the derived did:web belongs to another org.

Response 201

FieldTypeRequiredDescription
agent_didstringyesdid:web: derived from the org and the handle.
kidstringyes\<agent_did\>#\<n\>.
pubkeystringyesRaw 32-byte Ed25519 public key, base64.
status"active"yes

Example response

{
  "agent_did": "did:web:codespar.dev:org:agent",
  "kid": "string",
  "pubkey": "string",
  "status": "active"
}

Example request

curl -X POST https://api.codespar.dev/v1/orgs/{orgId}/agents \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "agent_id": "agt_0000000000000000",
       "display_name": "Example",
       "principal_ref": "string"
     }'

POST /v1/orgs/{orgId}/agents/{agentId}/keys/rotate

Retire the agent's active key and mint a fresh one

Path parameters

NameTypeRequiredDescription
agentIdstringyesThe registration handle, not the did:web.
orgIdstringyes

Responses

StatusBodyDescription
201objectOK
403objectThe \{orgId\} in the path is not the authenticated org.
404objectNo agent with that handle in this org.
409objectThe agent holds no active key to rotate.

Response 201

FieldTypeRequiredDescription
agent_didstringyes
kidstringyesThe new active key.
pubkeystringyesRaw 32-byte Ed25519 public key, base64.
retired_kidstringyesThe key just retired. It still verifies what it signed before retirement; it can only no longer sign anything new.
status"active"yes

Example response

{
  "agent_did": "did:web:codespar.dev:org:agent",
  "kid": "string",
  "pubkey": "string",
  "retired_kid": "string",
  "status": "active"
}

Example request

curl -X POST https://api.codespar.dev/v1/orgs/{orgId}/agents/{agentId}/keys/rotate \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

POST /v1/orgs/{orgId}/agents/{agentId}/keys/{kid}/revoke

Hard-revoke one of an agent's signing keys

Path parameters

NameTypeRequiredDescription
agentIdstringyesThe registration handle, not the did:web.
kidstringyes\<did:web:...\>#\<n\>, with the # percent-encoded as %23.
orgIdstringyes

Responses

StatusBodyDescription
200objectOK
403objectThe \{orgId\} in the path is not the authenticated org.
404objectNo such key for that agent in this org.
409objectThat key is already revoked.

Response 200

FieldTypeRequiredDescription
kidstringyes
revoked_atstring (date-time)yes
status"revoked"yes

Example response

{
  "kid": "string",
  "status": "revoked",
  "revoked_at": "2026-01-15T12:00:00.000Z"
}

Example request

curl -X POST https://api.codespar.dev/v1/orgs/{orgId}/agents/{agentId}/keys/{kid}/revoke \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/orgs/{orgId}/approvals/health

Queue depth and the age of the oldest pending approval

Path parameters

NameTypeRequiredDescription
orgIdstringyes

Responses

StatusBodyDescription
200objectOK
404objectNot Found

Response 200

FieldTypeRequiredDescription
last_sweep_atstring,null (date-time)yesDeployment-wide, not scoped to this org.
oldest_pending_age_secondsinteger,nullyesNull when nothing is pending. Rounded to whole seconds.
pending_countintegeryes
status"ok"yes

Example response

{
  "status": "ok",
  "pending_count": 1
}

Example request

curl -X GET https://api.codespar.dev/v1/orgs/{orgId}/approvals/health \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/orgs/{orgId}/approvals/{id}

Read one approval, including the tool arguments held for review

Path parameters

NameTypeRequiredDescription
idstringyes
orgIdstringyes

Responses

StatusBodyDescription
200objectOK
404objectNot Found

Response 200

FieldTypeRequiredDescription
agent_idstringyes
created_atstring (date-time)yes
decided_atstring,null (date-time)yes
decided_bystring,nullyes
decision_reasonstring,nullyes
executed_atstring,null (date-time)yes
execution_resultobject,nullyes
expires_atstring (date-time)yes
idstringyes
matched_rule_idstringyes
matched_rule_namestringyes
org_idstringyes
project_idstring,nullyes
session_idstring,nullyes
status"pending" | "approved" | "denied" | "expired" | "execution_failed"yesClosed by the table's own CHECK constraint, not by convention.
tool_inputobjectyesThe tool arguments the rule held for review, verbatim.
tool_namestringyes

Example response

{
  "id": "obj_0000000000000000",
  "org_id": "org_0000000000000000",
  "agent_id": "agt_0000000000000000",
  "matched_rule_id": "matchedrule_0000000000000000",
  "matched_rule_name": "Example",
  "tool_name": "Example",
  "tool_input": {},
  "status": "pending",
  "created_at": "2026-01-15T12:00:00.000Z",
  "expires_at": "2026-01-15T12:00:00.000Z"
}

Example request

curl -X GET https://api.codespar.dev/v1/orgs/{orgId}/approvals/{id} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/orgs/{orgId}/audit/config

Read the chain verification windows and staleness budgets

Path parameters

NameTypeRequiredDescription
orgIdstringyes

Responses

StatusBodyDescription
200objectOK
403objectThe \{orgId\} in the path is not the authenticated org.

Response 200

FieldTypeRequiredDescription
cold_max_staleness_secondsintegeryes
created_atstring (date-time)yes
hot_max_staleness_secondsintegeryes
hot_window_daysintegeryes
initial_walk_completed_atstring,null (date-time)yesNull until the first forward walk has reached the chain tip.
org_idstringyes
updated_atstring (date-time)yes
verification_window_daysintegeryes
warm_max_staleness_secondsintegeryes
warm_window_daysintegeryes

Example response

{
  "org_id": "org_0000000000000000",
  "verification_window_days": 0,
  "hot_window_days": 0,
  "hot_max_staleness_seconds": 1,
  "warm_window_days": 0,
  "warm_max_staleness_seconds": 1,
  "cold_max_staleness_seconds": 1,
  "created_at": "2026-01-15T12:00:00.000Z",
  "updated_at": "2026-01-15T12:00:00.000Z"
}

Example request

curl -X GET https://api.codespar.dev/v1/orgs/{orgId}/audit/config \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

PATCH /v1/orgs/{orgId}/audit/config

Update the chain verification windows and staleness budgets

Path parameters

NameTypeRequiredDescription
orgIdstringyes

Request body

FieldTypeRequiredDescription
cold_max_staleness_secondsnumberno
hot_max_staleness_secondsnumberno
hot_window_daysnumberno
verification_window_daysnumberno
warm_max_staleness_secondsnumberno
warm_window_daysnumberno

Responses

StatusBodyDescription
200objectOK
400object | objectThe merged config broke an invariant. limit carries the ceiling on regulatory_minimum_violation, and the three merged window values on window_ordering_invalid.
401objectNo x-codespar-user header on a service credential.
403objectThe \{orgId\} is not the authenticated org, a project API key was used, or the named user is below admin.

Response 200

FieldTypeRequiredDescription
cold_max_staleness_secondsintegeryes
created_atstring (date-time)yes
hot_max_staleness_secondsintegeryes
hot_window_daysintegeryes
initial_walk_completed_atstring,null (date-time)yesNull until the first forward walk has reached the chain tip.
org_idstringyes
updated_atstring (date-time)yes
verification_window_daysintegeryes
warm_max_staleness_secondsintegeryes
warm_window_daysintegeryes

Example response

{
  "org_id": "org_0000000000000000",
  "verification_window_days": 0,
  "hot_window_days": 0,
  "hot_max_staleness_seconds": 1,
  "warm_window_days": 0,
  "warm_max_staleness_seconds": 1,
  "cold_max_staleness_seconds": 1,
  "created_at": "2026-01-15T12:00:00.000Z",
  "updated_at": "2026-01-15T12:00:00.000Z"
}

Example request

curl -X PATCH https://api.codespar.dev/v1/orgs/{orgId}/audit/config \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "verification_window_days": 0,
       "hot_window_days": 0,
       "hot_max_staleness_seconds": 1,
       "warm_window_days": 0,
       "warm_max_staleness_seconds": 1,
       "cold_max_staleness_seconds": 1
     }'

GET /v1/orgs/{orgId}/audit/health

How far the chain verifier got, and whether what it walked was linked

Path parameters

NameTypeRequiredDescription
orgIdstringyes

Responses

StatusBodyDescription
200objectOK
403objectThe \{orgId\} in the path is not the authenticated org.

Response 200

FieldTypeRequiredDescription
actionable_status"verifying" | "healthy" | "catching_up" | "link_unverifiable" | "degraded" | "broken"yesThe field to alert on. link_unverifiable is not degraded: it means part of the chain was never verified either way, whereas degraded means tampering was detected.
detailstringyes
incidentsobjectyes
initial_walkobjectyes
last_checked_atstring (date-time)yes
last_sequence_numberintegeryes
status"healthy" | "degraded"yes
verificationobjectyes

Example response

{
  "status": "healthy",
  "last_sequence_number": 0,
  "last_checked_at": "2026-01-15T12:00:00.000Z",
  "detail": "string",
  "actionable_status": "verifying",
  "verification": {
    "window_days": 0,
    "watermark_sequence": 0,
    "coverage_ratio": 0,
    "hot_bucket_max_staleness_seconds": 1,
    "chain_link_check": {
      "unverifiable_segments": 0,
      "oldest_unverifiable_segment": {
        "from_sequence": 0,
        "to_sequence": 0,
        "reason": "sequence_gap",
        "first_detected_at": "2026-01-15T12:00:00.000Z"
      },
      "writer_tip_link_unverifiable": true
    }
  },
  "incidents": {
    "open_count": 1,
    "acknowledged_count_30d": 1,
    "open_truncated": true,
    "open": [
      {
        "id": "obj_0000000000000000",
        "detected_at": "2026-01-15T12:00:00.000Z",
        "detected_at_sequence": 0
      }
    ]
  },
  "initial_walk": {
    "in_progress": true,
    "events_processed": 0
  }
}

Example request

curl -X GET https://api.codespar.dev/v1/orgs/{orgId}/audit/health \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/orgs/{orgId}/audit/incidents

List chain-integrity incidents

Path parameters

NameTypeRequiredDescription
orgIdstringyes

Query parameters

NameTypeRequiredDescription
statusstringnoComma-separated, from open, acknowledged and all; all wins over anything sent with it. Default open. Unknown tokens are DROPPED rather than refused, and the request is only 400 invalid_status when nothing recognisable survives.

Responses

StatusBodyDescription
200objectOK
400objectNo recognisable value survived the status filter.
403objectThe \{orgId\} in the path is not the authenticated org.

Response 200

FieldTypeRequiredDescription
incidentsarray of objectyes

Example response

{
  "incidents": [
    {
      "id": "obj_0000000000000000",
      "org_id": "org_0000000000000000",
      "detected_at": "2026-01-15T12:00:00.000Z",
      "detected_at_sequence": 0,
      "status": "open",
      "anpd_notification_status": "not_required",
      "created_at": "2026-01-15T12:00:00.000Z"
    }
  ]
}

Example request

curl -X GET https://api.codespar.dev/v1/orgs/{orgId}/audit/incidents \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

POST /v1/orgs/{orgId}/audit/incidents/{id}/acknowledge

Acknowledge a chain-integrity incident and write the acknowledgement into the chain

Path parameters

NameTypeRequiredDescription
idstringyes
orgIdstringyes

Request body

FieldTypeRequiredDescription
affected_from_sequencenumber,nullnoSend with affected_to_sequence or with neither; one without the other is 400 paired_required. The route checks only that the value is a JSON number and that from is not greater than to. It does NOT check integrality, so this schema does not claim an integer the route would accept a fraction for; send whole numbers, because the column behind it is an integer.
affected_to_sequencenumber,nullnoPaired with affected_from_sequence; same rules.
anpd_notification_status"not_required" | "notified"yesRequired and terminal. pending_assessment is refused with 400 pending_assessment_not_terminal: it is a console state and is never persisted.
incident_referencestring,nullnoOptional. Control-stripped first; the 256 character ceiling is applied to the stripped value. Unlike resolution_summary this one is not trimmed and an empty string is accepted.
personal_data_affectedbooleanyes
resolution_summarystringyesRequired, and whitespace alone does not satisfy it. The route strips C0 control characters and DEL, then refuses a value whose TRIMMED remainder is empty with 400 field_invalid / empty — so " " is rejected, not accepted. The 8000 character ceiling is then applied to the stripped value BEFORE trimming, so surrounding whitespace does count against the limit even though it cannot satisfy the emptiness check.

Responses

StatusBodyDescription
200objectOK
400object | objectA terminal ANPD status is required, or one field failed its check. field names it and reason is one of empty, too_long, invalid_type, invalid_enum, paired_required or range_inconsistent; limit is present only on too_long. resolution_summary reports empty both when it is missing or not a string and when it is present but blank after trimming.
401objectNo x-codespar-user header on a service credential.
403objectA project API key cannot acknowledge, or the named user is below admin.
404objectNo such incident for this org.
409objectAlready acknowledged. The current row is attached, so a retry needs no second read.
503objectThe per-org chain lock was not available. Nothing was written; retry.

Response 200

FieldTypeRequiredDescription
chain_sequence_numberintegeryesSequence of the chain entry this acknowledgement appended.
incidentobjectyes

Example response

{
  "incident": {
    "id": "obj_0000000000000000",
    "org_id": "org_0000000000000000",
    "detected_at": "2026-01-15T12:00:00.000Z",
    "detected_at_sequence": 0,
    "status": "open",
    "anpd_notification_status": "not_required",
    "created_at": "2026-01-15T12:00:00.000Z"
  },
  "chain_sequence_number": 0
}

Example request

curl -X POST https://api.codespar.dev/v1/orgs/{orgId}/audit/incidents/{id}/acknowledge \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "resolution_summary": "string",
       "anpd_notification_status": "not_required",
       "personal_data_affected": true
     }'

POST /v1/orgs/{orgId}/data-subjects/{userId}/anonymize

Erase a data subject's personal data across the audit chain (LGPD Art. 18)

Path parameters

NameTypeRequiredDescription
orgIdstringyes
userIdstringyes1 to 256 characters.

Responses

StatusBodyDescription
200objectOK
400object\{userId\} was empty or over 256 characters.
403objectThe \{orgId\} in the path is not the authenticated org.

Response 200

FieldTypeRequiredDescription
deferred_entriesarray of objectyes
dsr_event_entry_hashstringyes
dsr_idstringyesThe entry hash of the dsr_request chain event this call wrote.
rows_anonymized_immediatelyintegeryes
rows_deferredintegeryes

Example response

{
  "dsr_id": "dsr_0000000000000000",
  "dsr_event_entry_hash": "string",
  "rows_anonymized_immediately": 0,
  "rows_deferred": 0,
  "deferred_entries": [
    {
      "event_id": "event_0000000000000000",
      "anonymize_after": "2026-01-15T12:00:00.000Z"
    }
  ]
}

Example request

curl -X POST https://api.codespar.dev/v1/orgs/{orgId}/data-subjects/{userId}/anonymize \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/orgs/{orgId}/mandates

List the org's mandates

Path parameters

NameTypeRequiredDescription
orgIdstringyes

Query parameters

NameTypeRequiredDescription
agent_idstringno
created_afterinteger,nullno
limitintegerno
status"active" | "revoked" | "expired"no

Responses

StatusBodyDescription
200objectOK
400objectThe query failed the schema; details.issues carries the Zod issues.

Response 200

FieldTypeRequiredDescription
countintegeryesLength of mandates, not a total.
mandatesarray of objectyes

Example response

{
  "mandates": [
    {
      "id": "obj_0000000000000000",
      "org_id": "org_0000000000000000",
      "agent_id": "agt_0000000000000000",
      "type": "payment",
      "status": "active",
      "format_version": 0,
      "secret_version": 0,
      "amount": "1000",
      "remaining_amount": "1000",
      "currency": "BRL",
      "purposes": [
        "string"
      ],
      "expires_at": "2026-01-15T12:00:00.000Z",
      "signature": "string",
      "authorized_by": "string",
      "created_at": "2026-01-15T12:00:00.000Z"
    }
  ],
  "count": 1
}

Example request

curl -X GET https://api.codespar.dev/v1/orgs/{orgId}/mandates \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

POST /v1/orgs/{orgId}/mandates

Issue an org-side mandate (off by default, see the 501)

Path parameters

NameTypeRequiredDescription
orgIdstringyes

Request body

FieldTypeRequiredDescription
agent_idstringyes
amountstringyes
currencystringyes
denominationstring,nullno
expires_atintegeryes
max_amountstring,nullno
parent_idstring,nullno
purposesarray of stringyes
type"payment" | "subscription" | "delegation"yes

Responses

StatusBodyDescription
201object | objectOK
400objectThe body failed the schema (details.issues carries the Zod issues), expires_at was not in the future, or a purpose was not printable ASCII.
403objectA policy rule refused issuance. details carries reason, ruleType and ruleId, plus approval_id and expires_at when the rule opened an approval instead of denying outright.
413objectThe policy input was too large to evaluate.
501objectOrg-side issuance is disabled on this deployment. No mandate was created.
503objectThe policy engine could not evaluate the request. Nothing was evaluated and nothing was issued; retry.

Example response

{
  "mandate_id": "mandate_0000000000000000",
  "signed_token": "string",
  "format_version": 3,
  "agent_did": "did:web:codespar.dev:org:agent",
  "kid": "string",
  "principal_kyc_verified": false,
  "expires_at": "2026-01-15T12:00:00.000Z"
}

Example request

curl -X POST https://api.codespar.dev/v1/orgs/{orgId}/mandates \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "agent_id": "agt_0000000000000000",
       "type": "payment",
       "amount": "1000",
       "currency": "BRL",
       "purposes": [
         "string"
       ],
       "expires_at": 0
     }'

GET /v1/orgs/{orgId}/mandates/{id}

Read one mandate with its consumption history

Path parameters

NameTypeRequiredDescription
idstringyes
orgIdstringyes

Responses

StatusBodyDescription
200objectOK
404objectNo such mandate for this org.

Response 200

FieldTypeRequiredDescription
agent_idstringyes
amountstringyesDecimal string.
authorized_bystringyes
consumptionsarray of objectyes
created_atstring (date-time)yes
currencystringyes
denominationstring,nullyes
expired_atstring,null (date-time)yes
expires_atstring (date-time)yes
format_versionintegeryes
idstringyesmnd_ prefixed.
max_amountstring,nullyes
org_idstringyes
parent_idstring,nullyes
purposesarray of stringyes
remaining_amountstringyesDecimal string, and it MOVES. This is the aggregate cap still available on the mandate: POST /v1/wallets/\{id\}/execute charges this mandate before the payment is attempted, decrementing this value and recording the consumption in one transaction. A spend that would take it below zero is refused with mandate_cap_exceeded rather than clamped, so this never goes negative.
revocation_reasonstring,nullyes
revoked_atstring,null (date-time)yes
secret_versionintegeryes
signaturestringyes
status"active" | "revoked" | "expired"yesClosed by the table's own CHECK constraint.
type"payment" | "subscription" | "delegation"yes

Example response

{
  "id": "obj_0000000000000000",
  "org_id": "org_0000000000000000",
  "agent_id": "agt_0000000000000000",
  "type": "payment",
  "status": "active",
  "format_version": 0,
  "secret_version": 0,
  "amount": "1000",
  "remaining_amount": "1000",
  "currency": "BRL",
  "purposes": [
    "string"
  ],
  "expires_at": "2026-01-15T12:00:00.000Z",
  "signature": "string",
  "authorized_by": "string",
  "created_at": "2026-01-15T12:00:00.000Z",
  "consumptions": [
    {
      "id": "obj_0000000000000000",
      "mandate_id": "mandate_0000000000000000",
      "amount": "1000",
      "call_purpose": "string",
      "tool_call_id": "tc_0000000000000000",
      "consumed_at": "2026-01-15T12:00:00.000Z"
    }
  ]
}

Example request

curl -X GET https://api.codespar.dev/v1/orgs/{orgId}/mandates/{id} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

POST /v1/orgs/{orgId}/mandates/{id}/revoke

Revoke a mandate

Path parameters

NameTypeRequiredDescription
idstringyes
orgIdstringyes

Request body

FieldTypeRequiredDescription
reasonstringnoFree text, trimmed. An absent, non-string or blank value is recorded as revoked by operator.

Responses

StatusBodyDescription
200objectOK
404objectNo such mandate for this org.
409objectThe mandate was already revoked.
410objectThe mandate had already expired.

Response 200

FieldTypeRequiredDescription
prior_status"active"yes
revoked_atstring (date-time)yes

Example response

{
  "revoked_at": "2026-01-15T12:00:00.000Z",
  "prior_status": "active"
}

Example request

curl -X POST https://api.codespar.dev/v1/orgs/{orgId}/mandates/{id}/revoke \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "reason": "string"
     }'
Orgs | CodeSpar