Skip to main content

Mandates

Generated HTTP reference for the 5 operations the published OpenAPI document describes under mandates.

7 min read
View MarkdownEdit on GitHub

Mandates

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.

These five operations read and transition a consumer mandate: the allowance a consumer signed for one agent, with a purpose, a payee allowlist, per-currency caps and an expiry. None of them creates one. A mandate is born in the consent flow (POST /v1/consents/init, then the consumer signs at the hosted page) and is signed server-side, so there is no signing step on your side. The concept page, Mandates, receipts and approvals, has the matrix of what exists per channel (REST, SDK, CLI, dashboard, meta-tool), the lifecycle, and what is still not in this document.

The same four transitions are also registered under /v1/consumers/mandates/{id}/..., the older spelling. They are not in this document; the canonical paths below are the ones to call.

Every operation, from the spec

Generated from the published OpenAPI document, so it never drifts from what the API actually serves. The section above is written by hand and carries what a schema cannot: the object model, field rules, and the order to call things in.

GET /v1/mandates

GEThttps://api.codespar.dev/v1/mandates

List consumer allowances

Query parameters

NameTypeRequiredDescription
consumer_idstringno
limitintegerno
status"active" | "paused" | "revoked" | "expired"no

Responses

StatusBodyDescription
200objectOK
400objectThe query did not match the schema: an unknown status, a limit outside 1..200, or a limit that is not a number. details.issues carries the Zod issues.

Response 200

FieldTypeRequiredDescription
mandatesarray of objectyes
Example request
curl -X GET https://api.codespar.dev/v1/mandates \
  -H "Authorization: Bearer $CODESPAR_API_KEY"
const res = await fetch("https://api.codespar.dev/v1/mandates", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
  },
});

const data = await res.json();
const result = await cs.api.get("/v1/mandates");
Example response 200
application/json
{
  "mandates": [
    {
      "id": "obj_0000000000000000",
      "consumer_id": "csm_0000000000000000",
      "agent_id": "agt_0000000000000000",
      "purpose": "string",
      "merchant_allowlist": [
        "string"
      ],
      "merchant_pin_kind": "pix-key",
      "cap_minor": "1000",
      "per_tx_cap_minor": "1000",
      "currency": "BRL",
      "status": "active",
      "expires_at": "2026-01-15T12:00:00.000Z",
      "created_at": "2026-01-15T12:00:00.000Z"
    }
  ]
}

GET /v1/mandates/{id}

GEThttps://api.codespar.dev/v1/mandates/{id}

Read one consumer allowance

Path parameters

NameTypeRequiredDescription
idstringyes

Responses

StatusBodyDescription
200objectOK
404objectNo such allowance for this credential's organization. An allowance belonging to another organization answers exactly the same way: the org predicate sits in the SELECT, so the handler cannot tell absent from someone else's, and must not.

Response 200

FieldTypeRequiredDescription
agent_idstringyesThe agent this allowance authorizes to spend.
cap_minorstringyesTotal spend authorized over the life of the allowance, in minor units. A STRING: the column is bigint and the driver hands it back as text, so parse it as an integer and never as a float.
consumer_idstringyes
created_atstring (date-time)yes
currencystringyesLeft open here rather than closed. The column admits BRL, USD, MXN, COP, ARS, USDC and BRLA today, and that list is a CHECK constraint on our side rather than a promise on the wire.
display_namestring,nullyes
expires_atstring (date-time)yesNever null: the column is NOT NULL.
idstringyes
intent_notestring,nullyes
merchant_allowlistarray of stringyesThe payees this allowance may pay, read as merchant_pin_kind says to read them. Never empty: consumer_mandates_allowlist_nonempty refuses a row whose allowlist is not an array of at least one entry, so an allowance that authorizes nothing cannot exist.
merchant_pin_kind"pix-key" | "merchant-id" | "mcc"yesHow each allowlist entry pins a payee. The v1 rail pins by Pix key.
per_tx_cap_minorstringyesPer-transaction ceiling, in minor units. Same string shape as cap_minor.
purposestringyes
status"active" | "paused" | "revoked" | "expired"yes
Example request
curl -X GET https://api.codespar.dev/v1/mandates/{id} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"
const res = await fetch("https://api.codespar.dev/v1/mandates/{id}", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
  },
});

const data = await res.json();
const result = await cs.api.get("/v1/mandates/{id}", {
  path: {
    id: "mandate_0000000000000000"
  }
});
Example response 200
application/json
{
  "id": "obj_0000000000000000",
  "consumer_id": "csm_0000000000000000",
  "agent_id": "agt_0000000000000000",
  "purpose": "string",
  "merchant_allowlist": [
    "string"
  ],
  "merchant_pin_kind": "pix-key",
  "cap_minor": "1000",
  "per_tx_cap_minor": "1000",
  "currency": "BRL",
  "status": "active",
  "expires_at": "2026-01-15T12:00:00.000Z",
  "created_at": "2026-01-15T12:00:00.000Z"
}

POST /v1/mandates/{id}/pause

POSThttps://api.codespar.dev/v1/mandates/{id}/pause

Pause an allowance

Path parameters

NameTypeRequiredDescription
idstringyes

Request body

FieldTypeRequiredDescription
reasonstringnoRecorded in the evidence row's metadata, alongside the from/to pair. Not echoed in the response.

Responses

StatusBodyDescription
200objectOK
400objectA body was sent and did not match the schema. details.issues carries the Zod issues.
404objectNo such allowance for this credential's organization. An allowance belonging to another organization answers exactly the same way: the org predicate sits in the SELECT, so the handler cannot tell absent from someone else's, and must not.
409objectinvalid_transition when the allowance's current status is not a legal source for this verb. transition_conflict when another request moved the allowance between this one's read and its write: the UPDATE is guarded on the status that was read, so a concurrent transition loses rather than double-applying, and the evidence row is written in the same transaction as the status change or not at all.

Response 200

FieldTypeRequiredDescription
changedbooleanyesFalse when the allowance was already in this state. Nothing was written and no evidence row was appended.
mandateobjectyes
Example request
curl -X POST https://api.codespar.dev/v1/mandates/{id}/pause \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "reason": "string"
     }'
const res = await fetch("https://api.codespar.dev/v1/mandates/{id}/pause", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "reason": "string"
  }),
});

const data = await res.json();
const result = await cs.api.post("/v1/mandates/{id}/pause", {
  path: {
    id: "mandate_0000000000000000"
  },
  body: {
    reason: "string"
  }
});
Example response 200
application/json
{
  "mandate": {
    "id": "obj_0000000000000000",
    "status": "paused"
  },
  "changed": true
}

POST /v1/mandates/{id}/resume

POSThttps://api.codespar.dev/v1/mandates/{id}/resume

Resume a paused allowance

Path parameters

NameTypeRequiredDescription
idstringyes

Request body

FieldTypeRequiredDescription
reasonstringnoRecorded in the evidence row's metadata, alongside the from/to pair. Not echoed in the response.

Responses

StatusBodyDescription
200objectOK
400objectA body was sent and did not match the schema. details.issues carries the Zod issues.
404objectNo such allowance for this credential's organization. An allowance belonging to another organization answers exactly the same way: the org predicate sits in the SELECT, so the handler cannot tell absent from someone else's, and must not.
409objectinvalid_transition when the allowance's current status is not a legal source for this verb. transition_conflict when another request moved the allowance between this one's read and its write: the UPDATE is guarded on the status that was read, so a concurrent transition loses rather than double-applying, and the evidence row is written in the same transaction as the status change or not at all.

Response 200

FieldTypeRequiredDescription
changedbooleanyesFalse when the allowance was already in this state. Nothing was written and no evidence row was appended.
mandateobjectyes
Example request
curl -X POST https://api.codespar.dev/v1/mandates/{id}/resume \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "reason": "string"
     }'
const res = await fetch("https://api.codespar.dev/v1/mandates/{id}/resume", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "reason": "string"
  }),
});

const data = await res.json();
const result = await cs.api.post("/v1/mandates/{id}/resume", {
  path: {
    id: "mandate_0000000000000000"
  },
  body: {
    reason: "string"
  }
});
Example response 200
application/json
{
  "mandate": {
    "id": "obj_0000000000000000",
    "status": "active"
  },
  "changed": true
}

POST /v1/mandates/{id}/revoke

POSThttps://api.codespar.dev/v1/mandates/{id}/revoke

Revoke an allowance

Path parameters

NameTypeRequiredDescription
idstringyes

Request body

FieldTypeRequiredDescription
reasonstringnoRecorded in the evidence row's metadata, alongside the from/to pair. Not echoed in the response.

Responses

StatusBodyDescription
200objectOK
400objectA body was sent and did not match the schema. details.issues carries the Zod issues.
404objectNo such allowance for this credential's organization. An allowance belonging to another organization answers exactly the same way: the org predicate sits in the SELECT, so the handler cannot tell absent from someone else's, and must not.
409objectinvalid_transition when the allowance's current status is not a legal source for this verb. transition_conflict when another request moved the allowance between this one's read and its write: the UPDATE is guarded on the status that was read, so a concurrent transition loses rather than double-applying, and the evidence row is written in the same transaction as the status change or not at all.

Response 200

FieldTypeRequiredDescription
changedbooleanyesFalse when the allowance was already in this state. Nothing was written and no evidence row was appended.
mandateobjectyes
Example request
curl -X POST https://api.codespar.dev/v1/mandates/{id}/revoke \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "reason": "string"
     }'
const res = await fetch("https://api.codespar.dev/v1/mandates/{id}/revoke", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CODESPAR_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "reason": "string"
  }),
});

const data = await res.json();
const result = await cs.api.post("/v1/mandates/{id}/revoke", {
  path: {
    id: "mandate_0000000000000000"
  },
  body: {
    reason: "string"
  }
});
Example response 200
application/json
{
  "mandate": {
    "id": "obj_0000000000000000",
    "status": "revoked"
  },
  "changed": true
}
Mandates | CodeSpar