Skip to main content
API reference

Consumers

Generated HTTP reference for the 22 operations the published OpenAPI document describes under consumers.

29 min read
View MarkdownEdit on GitHub

Consumers

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.

GET /v1/consumers

List titulars

Query parameters

NameTypeRequiredDescription
limitintegerno
verified"true" | "false"no

Responses

StatusBodyDescription
200objectOK
400objectBad Request — the body or query did not match the schema.

Response 200

FieldTypeRequiredDescription
consumersarray of objectyes

Example response

{
  "consumers": [
    {
      "id": "obj_0000000000000000",
      "metadata": {},
      "status": "unverified",
      "created_at": "string"
    }
  ]
}

Example request

curl -X GET https://api.codespar.dev/v1/consumers \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

POST /v1/consumers

Create the titular, without a document

Request body

FieldTypeRequiredDescription
display_namestringno
metadataobjectno

Responses

StatusBodyDescription
201objectOK
400objectBad Request — the body or query did not match the schema.

Response 201

FieldTypeRequiredDescription
created_atstringyes
display_namestring,nullyes
documentstring,nullyes
document_sourcestring,nullyes
document_verified_atstring,nullyes
idstringyes
metadataobjectyes
person_typestring,nullyes
status"unverified" | "verified"yes
tax_typestring,nullyes

Example response

{
  "id": "obj_0000000000000000",
  "metadata": {},
  "status": "unverified",
  "created_at": "string"
}

Example request

curl -X POST https://api.codespar.dev/v1/consumers \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "display_name": "Example",
       "metadata": {}
     }'

GET /v1/consumers/mandates/{id}/card

The card bound to a mandate, and its recent authorizations

Path parameters

NameTypeRequiredDescription
idstringyesThe mandate id.

Query parameters

NameTypeRequiredDescription
limitintegernoAuthorizations to return. Default 20, clamped to the range 1 to 100.

Responses

StatusBodyDescription
200objectOK
404objectNo such mandate for this organization. A mandate another organization holds answers the same way.

Response 200

FieldTypeRequiredDescription
authorizationsarray of objectyesNewest first. Empty when no card is bound.
cardobject,nullyesNull when the mandate exists and has no active card binding.
mandate_idstringyes

Example response

{
  "mandate_id": "mandate_0000000000000000",
  "card": {
    "card_id": "card_0000000000000000",
    "consumer_id": "csm_0000000000000000",
    "status": "string",
    "bound_at": "2026-01-15T12:00:00.000Z"
  },
  "authorizations": [
    {
      "transaction_id": "transaction_0000000000000000",
      "amount_minor": "1000",
      "currency": "BRL",
      "decision": "string",
      "at": "2026-01-15T12:00:00.000Z"
    }
  ]
}

Example request

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

DELETE /v1/consumers/mandates/{id}/card

Unbind the card from a mandate

Path parameters

NameTypeRequiredDescription
idstringyesThe mandate id.

Responses

StatusBodyDescription
200objectOK
404objectmandate_not_found: no such mandate for this organization, which is also the answer for another organization's mandate. no_active_card: the mandate exists and has no active card binding to revoke.

Response 200

FieldTypeRequiredDescription
card_idstringyes
mandate_idstringyes
revokedtrueyes

Example response

{
  "mandate_id": "mandate_0000000000000000",
  "card_id": "card_0000000000000000",
  "revoked": true
}

Example request

curl -X DELETE https://api.codespar.dev/v1/consumers/mandates/{id}/card \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/consumers/receipts/{id}

Read one agentic receipt

Path parameters

NameTypeRequiredDescription
idstringyesThe receipt id.

Responses

StatusBodyDescription
200objectOK
404objectNo receipt with this id in this project. A receipt in another project of the same organization answers the same way.

Response 200

FieldTypeRequiredDescription
chainstringyes
deliveryobject,nullyesNull until a delivery proof has been sealed onto the receipt.
exceptionsarray of objectyes
mandateobjectyes
paymentobjectyes
quoteobject,nullyesNull when the receipt carries neither a seller nor a resource.
receipt_idstringyes
receipt_sigstringyes
state"paid" | "delivered" | "exception" | "voided"yes

Example response

{
  "receipt_id": "receipt_0000000000000000",
  "state": "paid",
  "mandate": {
    "id": "obj_0000000000000000",
    "nonce": "string",
    "scope": "string",
    "currency": "BRL",
    "sig": "string"
  },
  "quote": {},
  "payment": {
    "rail": "string",
    "amount_minor": 1000,
    "amount_authorized": "1000",
    "amount_charged": "1000",
    "amount_refunded": "1000",
    "metering": {
      "basis": "string",
      "units": "string",
      "unit_price": "string"
    },
    "sandbox": true,
    "attempt_id": "attempt_0000000000000000",
    "money_moved": true,
    "at": "string"
  },
  "delivery": {
    "result": "confirmed"
  },
  "chain": "string",
  "receipt_sig": "string",
  "exceptions": [
    {
      "code": "string",
      "detail": "string",
      "at": "string"
    }
  ]
}

Example request

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

POST /v1/consumers/{consumerId}/contact-verifications

Send a one-time code to a consumer's e-mail address or phone number

Path parameters

NameTypeRequiredDescription
consumerIdstringyes

Request body

FieldTypeRequiredDescription
channel"email" | "phone"yes
localestringno
targetstringyes

Responses

StatusBodyDescription
201objectOK
400objectinvalid_body: the body did not match the schema, and details.issues carries the validation errors. invalid_target: the contact does not canonicalize for this channel.
422objectno_celcoin_account: the consumer has no active pix-celcoin funding source in this organization — or is not this organization's consumer at all. otp_sender_refused: the sender refused to deliver to this number and repeating will not change that; details.provider names which sender said so. Nothing was sent, and no attempt was consumed, in either case.
429objecttoo_many_requests: the per-contact hourly ceiling was reached. details.window_seconds and details.max_sends give the window and the ceiling. Nothing was sent.
500object | objectTwo different bodies, because two different failures land here. contact_verification_error in the usual error envelope: an unclassified failure while starting. Nothing was sent that could be verified. THE OTHER SHAPE IS NOT THAT ENVELOPE. Resolving the consumer's account runs before the handler's own error handling, so a failure there is answered by the framework's default: \{ statusCode, error, message \}, plus code when the underlying failure carried one. A client that parses error.code will find error is a STRING here. Nothing was sent in this case either.
503objectotp_sender_unavailable, and the three conditions behind it DO NOT agree on whether a retry is free. 1. No sender is configured for this channel on the deployment. Nothing was written and nothing was sent; retrying changes nothing until the deployment does. 2. The send itself did not complete. The verification row is removed, so the attempt does not count against the hourly ceiling and a retry is free. Removal is best effort: if it fails the row stands, unverifiable, and does consume one of the hour's sends. 3. THE CODE REACHED THE CONTACT and the row could not be completed. The row STANDS and DOES count against the hourly ceiling, and the consumer may receive a code that can never be verified. details.verification_id is present, and it is present ONLY in this case — that is how a caller tells the free retry from the expensive one.

Response 201

FieldTypeRequiredDescription
channel"email" | "phone"yes
expires_atstring (date-time)yesMAY ALREADY BE IN THE PAST. A second start for the same contact supersedes the earlier one by closing its validity, and if that lands while this send is in flight the row keeps the closed expiry and this field reports it. A superseded code answers 410 on verify.
idstring (uuid)yesSend this back in the /verify step.
provider"dev" | "prelude" | "resend"yesWhich sender delivered, and it decides the /verify step: prelude checks the code against the contact itself, so target is REQUIRED there. The other two are checked locally and do not need it.
status"sent"yes
target_maskedstringyesThe masked contact. The full value never comes back: the row keeps a keyed hash.

Example response

{
  "id": "obj_0000000000000000",
  "channel": "email",
  "target_masked": "string",
  "provider": "dev",
  "expires_at": "2026-01-15T12:00:00.000Z",
  "status": "sent"
}

Example request

curl -X POST https://api.codespar.dev/v1/consumers/{consumerId}/contact-verifications \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "channel": "email",
       "target": "string",
       "locale": "string"
     }'

POST /v1/consumers/{consumerId}/contact-verifications/{id}/verify

Check the code the consumer received

Path parameters

NameTypeRequiredDescription
consumerIdstringyes
idstring (uuid)yes

Request body

FieldTypeRequiredDescription
codestringyes
targetstringno

Responses

StatusBodyDescription
200objectOK
400objectinvalid_body: the body did not match the schema (details.issues). invalid_code: the code is not 4-8 digits, or it does not match; details.attempts_left says what is left, and only the second of those spent an attempt. invalid_target: this verification is checked against the contact and target did not come with the code.
404objectnot_found: there is no verification with this id for this consumer. It covers a malformed id, a row of another consumer, a row of another organization, a row whose send never completed, and a target that does not hash to the row's — that last one having spent an attempt.
410objectverification_expired: the code expired, or a later send superseded it, or the sender itself reports it expired. Start a new verification.
429objecttoo_many_attempts: this verification has spent every attempt. There is no reset; start a new one.
500objectcontact_verification_error: an unclassified failure while checking. This operation reads nothing outside its own error handling, so this is its only 500 body.
503objectotp_sender_unavailable covers two conditions that cost different things. THE PROVIDER DID NOT ANSWER the check. The attempt was reserved before the call, so it IS spent and is not given back — returning it would reopen the race the reservation closes. details.attempts_left says how many remain. NO SENDER FOR THIS ROW'S PROVIDER exists on this deployment. The verify goes back to whichever sender delivered, whatever the deployment is configured for today, and this check runs BEFORE the reservation: NO attempt was spent and the response carries no details at all. Nothing the caller does resolves it — start a new verification, which will be sent through a sender that exists.

Response 200

FieldTypeRequiredDescription
idstring (uuid)yes
status"verified"yes
verified_atstring (date-time)yes

Example response

{
  "id": "obj_0000000000000000",
  "status": "verified",
  "verified_at": "2026-01-15T12:00:00.000Z"
}

Example request

curl -X POST https://api.codespar.dev/v1/consumers/{consumerId}/contact-verifications/{id}/verify \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "code": "string",
       "target": "string"
     }'

GET /v1/consumers/{consumerId}/dda/boletos

The boletos DDA has mirrored for this consumer

Path parameters

NameTypeRequiredDescription
consumerIdstringyes

Query parameters

NameTypeRequiredDescription
from_datestringyes
to_datestringyes

Responses

StatusBodyDescription
200objectOK
400objectfrom_date or to_date is missing or is not YYYY-MM-DD. details.issues carries the validation issues.

Response 200

FieldTypeRequiredDescription
boletosarray of objectyes
countintegeryesThe length of boletos. No pagination, so this is the total for the window.
from_datestringyesEchoes the validated from_date query parameter, so exactly YYYY-MM-DD.
to_datestringyesEchoes the validated to_date query parameter, so exactly YYYY-MM-DD.

Example response

{
  "from_date": "string",
  "to_date": "string",
  "count": 1,
  "boletos": [
    {
      "linha_digitavel": "string",
      "status": "string"
    }
  ]
}

Example request

curl -X GET https://api.codespar.dev/v1/consumers/{consumerId}/dda/boletos \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

POST /v1/consumers/{consumerId}/dda/subscriptions

Register the consumer's CPF/CNPJ with DDA

Path parameters

NameTypeRequiredDescription
consumerIdstringyes

Request body

FieldTypeRequiredDescription
client_namestringno
documentstringyes
idempotency_keystringyes

Responses

StatusBodyDescription
200objectNothing was registered by this call: an attempt under this same key already holds the registration, or one is in flight. replayed is true and status is the row's current state.
201objectThis call registered the document. replayed is false and status is pending.
400objectinvalid_body, from three places: the body did not match the schema (and only then is details.issues present); document carries no CPF/CNPJ digits; idempotency_key is blank. Nothing was registered.
403objectdda_document_not_owned: the document is not the one verified for this consumer, or the consumer entity and the funding source disagree about who this consumer is. dda_document_unauthorized: no active mandate names this document in its signed allowlist. Nothing was registered, and neither carries details.
422objectno_celcoin_account: the consumer has no active pix-celcoin funding source in this organization — or is not this organization's consumer at all. dda_document_not_owned ALSO answers 422, and only for one cause: the account has no verified document on file at all, so no document can be shown to be theirs. Sending a different document will not help; finish onboarding and retry.
500object | objectNOT the usual error envelope. Three reads — the consumer's account, the verified document, and the authorizing mandate — run before the handler's own error handling, so a failure in any of them is answered by the framework's default: \{ statusCode, error, message \}, plus code when the underlying failure carried one. All three sit before the provider is called, so nothing was registered.
502objectdda_provider_unavailable, from two conditions the response does not separate: the provider answered and the answer was not a success (the local row is marked error), or the call was in flight and whether it arrived is genuinely not known here. Because the caller cannot tell them apart, the guidance is the same for both — retry with the SAME idempotency_key, which makes the retry the same registration rather than a second one.
503objectdda_claim_unavailable: the local claim failed and NOTHING was sent to the provider. This is stated apart from the 502 on purpose — here it is PROVEN that nothing left. Retry with the SAME idempotency_key.

Response 200

FieldTypeRequiredDescription
client_request_idstringyesThe provider-side anchor for this registration. Derived from (organization, consumer, document, idempotency_key), so the SAME key against a DIFFERENT document is a DIFFERENT registration.
documentstringyesDigits only. This is the document the consumer SIGNED in the mandate's allowlist, not the spelling that arrived in the body.
mandate_idstringyesThe active mandate whose signed allowlist authorized this.
replayedbooleanyestrue when this call registered nothing. Either an earlier attempt under this key already holds the registration, or one is in flight right now.
status"pending" | "active" | "error" | "deleted"yesA registration this call made is always pending, and becomes active only when the provider's confirmation webhook lands. A 200 (nothing registered by this call) reports the row's current state, which can be any of the four.

Example response

{
  "document": "string",
  "status": "pending",
  "client_request_id": "clientrequest_0000000000000000",
  "mandate_id": "mandate_0000000000000000",
  "replayed": true
}

Example request

curl -X POST https://api.codespar.dev/v1/consumers/{consumerId}/dda/subscriptions \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "document": "string",
       "client_name": "Example",
       "idempotency_key": "string"
     }'

GET /v1/consumers/{consumerId}/dda/subscriptions/{document}

Read a DDA registration

Path parameters

NameTypeRequiredDescription
consumerIdstringyes
documentstringyesCPF or CNPJ. Punctuation is accepted and stripped.

Responses

StatusBodyDescription
200objectOK
400objectThe path's document carries no CPF/CNPJ digits.
404objectNo DDA registration for this consumer and document. Also the answer for a consumer another organization holds.

Response 200

FieldTypeRequiredDescription
celcoin_subscription_idstring,nullyesThe provider's own id, null until the confirmation webhook supplies it.
client_request_idstringyesThe idempotency correlation carried to the provider on the registration.
documentstringyesDigits only. The stored form, which is what the provider leg was sent.
status"pending" | "active" | "error" | "deleted"yespending until the provider's confirmation webhook lands. Nothing polls the provider for this: the webhook is the only source of a status change, so a registration can sit pending indefinitely if a delivery was lost.

Example response

{
  "document": "string",
  "status": "pending",
  "client_request_id": "clientrequest_0000000000000000"
}

Example request

curl -X GET https://api.codespar.dev/v1/consumers/{consumerId}/dda/subscriptions/{document} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

DELETE /v1/consumers/{consumerId}/dda/subscriptions/{document}

End a DDA registration

Path parameters

NameTypeRequiredDescription
consumerIdstringyes
documentstringyesCPF or CNPJ. Punctuation is accepted and stripped.

Responses

StatusBodyDescription
200objectOK
400objectThe path's document carries no CPF/CNPJ digits.
404objectNo DDA registration for this consumer and document. Also returned when the row disappeared between the ownership read and the provider call, because in that case nothing was sent upstream.
502objectThe registration could not be ended upstream. Nothing about the local row changed; retry later.

Response 200

FieldTypeRequiredDescription
documentstringyes
status"deleted"yes

Example response

{
  "document": "string",
  "status": "deleted"
}

Example request

curl -X DELETE https://api.codespar.dev/v1/consumers/{consumerId}/dda/subscriptions/{document} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/consumers/{consumerId}/fund/{txId}

Poll an onramp, and credit the wallet when it settles

Path parameters

NameTypeRequiredDescription
consumerIdstringyes
txIdstringyesThe ramp provider's transaction id, from the fund call.

Responses

StatusBodyDescription
200objectOK
404objectOne code, and THREE distinct failures collapse into it. The route answers 404 exactly when the provider lookup yields nothing, and that lookup gives up in three separate places: 1. NOT CONNECTED. The organization has no ramp-provider account in connected state. A caller that never completed the provider connection sees this on every poll, for every transaction id. 2. CREDENTIAL GONE. The connection row exists and still reads as connected, but its stored credential no longer dereferences: revoked, rotated, or vaulted under a scope that no longer matches the row. Nothing else about the connection looks broken, which is what makes this one hard to recognize from the outside. 3. THE PROVIDER DID NOT RETURN IT. Any non-2xx from the provider lands here. That covers both this credential has no such transaction and the provider is down or refused, and the two are NOT distinguished: an outage is indistinguishable from an unknown id at this boundary. Only the third is worth retrying, and the response does not say which one happened. So read a 404 as this API cannot currently see the transaction, never as the transaction does not exist, and in particular never as grounds for starting a second onramp for the same deposit.

Response 200

FieldTypeRequiredDescription
amount_minorintegeryesUSDC the wallet receives, in minor units. Only meaningful once the tx settles.
creditedbooleanyesTrue whenever this poll found the transaction in a terminal success state with a positive delivered amount, and therefore posted the ledger credit. It is true on EVERY such poll, not only the first: the credit deduplicates on a deterministic external reference derived from the transaction id, so the repeat post is a no-op. Read it as this transaction has settled and the credit exists, never as this call created the credit.
currencystringyes
statusstringyesThe ramp provider's status, lower-cased and passed through (awaiting_deposit, processing, completed, and others it may add). Not a closed set.
transaction_idstringyesEchoes the path parameter.

Example response

{
  "transaction_id": "transaction_0000000000000000",
  "status": "string",
  "amount_minor": 1000,
  "currency": "BRL",
  "credited": true
}

Example request

curl -X GET https://api.codespar.dev/v1/consumers/{consumerId}/fund/{txId} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/consumers/{consumerId}/pix-keys

List the Pix keys on the consumer's account

Path parameters

NameTypeRequiredDescription
consumerIdstringyes

Responses

StatusBodyDescription
200objectOK
422objectno_celcoin_account: the consumer has no active Pix funding source, so there is no account to list. pix_key_provider_refused: the provider adjudicated and said no; details.provider_code names its business code, and retrying the same input cannot succeed.
502objectThe listing could not be completed upstream. The outcome is unknown and the condition is transient; retry. details.provider_code still carries whatever code the body named, so a generic provider error is visible without being called terminal.

Response 200

FieldTypeRequiredDescription
account_maskedstringyesFour mask characters followed by the account's last two digits.
countintegeryes
keysarray of objectyes

Example response

{
  "account_masked": "string",
  "keys": [
    {
      "key": "string",
      "key_type": "string"
    }
  ],
  "count": 1
}

Example request

curl -X GET https://api.codespar.dev/v1/consumers/{consumerId}/pix-keys \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

POST /v1/consumers/{consumerId}/pix-keys

Register a Pix key on the consumer's account

Path parameters

NameTypeRequiredDescription
consumerIdstringyes

Request body

FieldTypeRequiredDescription
keystringno
key_type"EVP" | "CPF" | "CNPJ" | "EMAIL" | "PHONE"yes

Responses

StatusBodyDescription
201objectOK
400objectinvalid_body: the body did not match the schema (details.issues). pix_key_invalid: the value is not a valid key for the key_type asked for, or key came with an EVP request, or key was missing for every other type. Neither reached the provider.
403objectpix_key_document_mismatch: a CPF/CNPJ key whose value is not the account holder's own document. Refused locally, without calling the provider.
409objectpix_key_ownership_unverified: this e-mail or phone has no recent verification for this consumer. details carries the channel, the endpoint to call and the window a verification stays good for; start a contact verification, confirm the code, retry. Nothing reached the provider. pix_key_registration_uncertain: the registration was accepted and came back with no readable key, and the account's key list could not settle whether it landed. details carries retry_safe: false, inventory_known and inventory_count. LIST the keys instead of repeating the registration.
422objectno_celcoin_account: the consumer has no active pix-celcoin funding source in this organization — or is not this organization's consumer at all; nothing reached the provider. pix_key_provider_refused: the provider adjudicated and refused, with details.provider_status and details.provider_code (null when the body named no code); repeating the same input will not pass.
500object | objectNOT the usual error envelope. Resolving the consumer's account runs before the handler's own error handling, so a failure there is answered by the framework's default: \{ statusCode, error, message \}, plus code when the underlying failure carried one. It happens before the provider is called, so nothing was registered.
502objectpix_key_provider_unavailable, and THREE different failures produce it with THREE different details. Read the field, not the code. 1. A transient upstream failure — a 5xx, transport, credentials, a generic internal code, a codeless 429/408/404. details.provider_status and details.provider_code (null when the body named no code). 2. A registration that PROVABLY did not land: the account's key list answered and does not carry the key. details.verified_not_registered is true and details.inventory_count is the number of keys the list reported. There is NO provider_code here — no provider code was involved in reaching this conclusion. 3. Anything the handler did not classify. No details at all. All three are retriable; only the second one is retriable on evidence rather than on the absence of it.

Response 201

FieldTypeRequiredDescription
account_maskedstringyesThe account, masked to its last two digits.
cache_filledbooleanyesfalse when the key WAS registered but the local cache could not be filled. Not a registration failure.
keystringyesThe registered key. For EVP this is the random key the provider minted, and this response is the only place it appears in this call.
key_typestringyesThe type as the provider returned it. Deliberately an open string rather than the request's enum: the value comes back from upstream and is carried through untyped.
reconciledbooleanyestrue when the key returned here came from re-reading the account's key list, because the registration response was unreadable. The key belongs to the account; THIS call is not proven to be what created it.

Example response

{
  "key": "string",
  "key_type": "string",
  "account_masked": "string",
  "cache_filled": true,
  "reconciled": true
}

Example request

curl -X POST https://api.codespar.dev/v1/consumers/{consumerId}/pix-keys \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "key_type": "EVP",
       "key": "string"
     }'

DELETE /v1/consumers/{consumerId}/pix-keys/{key}

Delete a Pix key from the consumer's account

Path parameters

NameTypeRequiredDescription
consumerIdstringyes
keystringyesThe key value. Trimmed; an empty value is 400.

Responses

StatusBodyDescription
200objectOK
400objectThe key in the path is empty after trimming.
422objectno_celcoin_account: the consumer has no active Pix funding source. pix_key_provider_refused: the provider adjudicated and refused; retrying the same input cannot succeed. details.provider_code carries its business code.
502objectThe deletion could not be completed upstream. Whether the key is gone is unknown; retry, then list the keys to confirm.

Response 200

FieldTypeRequiredDescription
account_maskedstringyes
cache_clearedbooleanyesWhether the deleted key was the one this API had cached as the receiving key.
cache_refilled_withstring,nullyesWhen the cache was cleared, the account's remaining keys are re-read and one is cached back, preferring a non-EVP key. Null when nothing was cleared, nothing remains, or the inventory read did not answer.
deletedtrueyes
keystringyesThe canonical form actually sent upstream. A punctuated CPF or CNPJ is normalized before the delete, so this can differ from the value in the path.

Example response

{
  "key": "string",
  "account_masked": "string",
  "deleted": true,
  "cache_cleared": true
}

Example request

curl -X DELETE https://api.codespar.dev/v1/consumers/{consumerId}/pix-keys/{key} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/consumers/{consumerId}/pix/charges/{reference}

A minted Pix charge's state

Path parameters

NameTypeRequiredDescription
consumerIdstringyes
referencestringyesThe charge id, the mint's transaction id, or its client request id. Up to 128 characters of letters, digits, _ and -.

Responses

StatusBodyDescription
200objectOK
400objectreference does not look like any of the three identifiers this route resolves.
404objectNo Pix charge with this reference. Deliberately the same answer for a charge another organization holds.
409objectThe reference matches more than one charge, because one value can sit in one row's transaction id and another row's client request id. Query by the charge id instead.
500objectThe charge status could not be read.
502objectThe provider consult did not answer, or it answered for a DIFFERENT cob than this charge and was refused rather than reported as this charge's state. Nothing about the charge was changed; retry later. details.reason names which of the two it was.

Response 200

FieldTypeRequiredDescription
amount_minorintegeryes
charge_idstringyes
client_request_idstring,nullyesNull for a static cob.
created_atstring (date-time)yes
currencystringyes
providerobject,nullyesNull when the provider was not consulted: the charge is already terminal on our books, or it is a static cob carrying no identifier the consult accepts.
settled_atstring,null (date-time)yes
statusstringyesOur books: pending, settled or expired. Left open rather than enumerated because the value is carried as a plain string end to end.
status_messagestringyesProse written for the caller, explaining what the combination above does and does not prove.
transaction_idstring,nullyesThe provider transaction id recorded at mint.
wallet_idstringyes

Example response

{
  "charge_id": "charge_0000000000000000",
  "status": "string",
  "amount_minor": 1000,
  "currency": "BRL",
  "wallet_id": "wlt_0000000000000000",
  "created_at": "2026-01-15T12:00:00.000Z",
  "provider": {
    "result": "ok",
    "identity_verified": true
  },
  "status_message": "string"
}

Example request

curl -X GET https://api.codespar.dev/v1/consumers/{consumerId}/pix/charges/{reference} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/consumers/{consumerId}/pix/devolutions/{devolutionId}

A Pix devolution's state

Path parameters

NameTypeRequiredDescription
consumerIdstringyes
devolutionIdstringyes

Responses

StatusBodyDescription
200objectOK
404objectNot a known devolution for this consumer. The same opaque answer for a truly unknown id and for another tenant's.
500objectThe devolution status could not be read.

Response 200

FieldTypeRequiredDescription
amount_minorintegeryes
charge_idstring,nullyes
client_codestringyesThe server-minted idempotency correlation sent upstream.
created_atstring (date-time)yes
currency"BRL"yes
devolution_idstringyes
end_to_end_idstringyes
failure_reasonstring,nullyes
idempotent_replaybooleanyesAlways false on this read. The field is meaningful on the create, not here.
original_payment_idstring,nullyes
payment_direction"inbound" | "outbound"yesWhich side of the rail the ORIGINAL payment was on. inbound: the consumer received it and the money goes back to its payer. outbound: the consumer sent it and the money returns to the consumer.
provider_truth"statement" | "unavailable" | "not_checked"yesWhere the state above came from. not_checked: the row is already terminal. statement: the consumer's own account statement was read and settled the row if it showed the reversal. unavailable: the statement could not be fetched, so the recorded state is returned unchanged. A statement failure degrades this field; it never turns the read into an error.
reasonstringyesThe Pix return code.
return_identificationstring,nullyes
settled_atstring,null (date-time)yes
status"pending" | "accepted" | "settled" | "failed" | "uncertain"yesThe five values the table's CHECK constraint admits.
status_messagestringyes
wallet_idstring,nullyes

Example response

{
  "devolution_id": "devolution_0000000000000000",
  "status": "pending",
  "payment_direction": "inbound",
  "end_to_end_id": "endtoend_0000000000000000",
  "amount_minor": 1000,
  "currency": "BRL",
  "reason": "string",
  "client_code": "string",
  "created_at": "2026-01-15T12:00:00.000Z",
  "idempotent_replay": true,
  "status_message": "string",
  "provider_truth": "statement"
}

Example request

curl -X GET https://api.codespar.dev/v1/consumers/{consumerId}/pix/devolutions/{devolutionId} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/consumers/{consumerId}/pix/receivements/{endToEndId}

Did this specific Pix land on this consumer's account

Path parameters

NameTypeRequiredDescription
consumerIdstringyes
endToEndIdstringyesThe payment's end-to-end id, the reference the payer's receipt carries. 16 to 64 alphanumeric characters.

Responses

StatusBodyDescription
200objectOK
400objectendToEndId does not have the shape of an end-to-end id.
404objectNo receivement with this end-to-end id on this consumer's account. Also the answer when the movement exists but belongs to another account, which is what keeps a bearer identifier from probing across tenants.
409objectThe consumer has no active Pix funding source, so there is no account to bind the answer to. Checked BEFORE the provider is queried, so an unbindable consumer never causes a lookup on a bearer identifier.
500objectThe receivement status could not be read.
502objectThe provider consult did not answer, or answered in a shape this backend cannot tenant-bind or cannot classify. Fail-closed in all three cases; details.reason names which.

Response 200

FieldTypeRequiredDescription
amount_minorinteger,nullyesMinor-unit truth from OUR charge row. Null when uncorrelated.
charge_idstring,nullyes
charge_statusstring,nullyes
correlation"charge_matched" | "no_correlator_returned" | "no_charge_matched" | "charge_ambiguous" | "not_attempted"yesHow this receivement was tied to a charge on our books. None of the empty outcomes proves a credit is not coming: the reconciler matches the account STATEMENT on a field this consult never returns.
devolutionsarray of objectyesOur devolution rows keyed on this end-to-end id, whatever the movement type is.
end_to_end_idstringyes
initiation_typestring,nullyes
provider_amountnoThe provider's own representation of the amount, passed through unconverted.
provider_transaction_idstring,nullyes
provider_transaction_typestringyesThe provider's discriminator, verbatim.
receivedbooleanyesTrue only when the provider classifies the movement as the homologated inbound type. A movement of another type on the same account (a reversal of a Pix the consumer SENT, for one) answers false with the type named below.
status_messagestringyes
transaction_id_brcodestring,nullyes
transaction_identificationstring,nullyes
wallet_creditedbooleanyes
wallet_idstring,nullyes

Example response

{
  "end_to_end_id": "endtoend_0000000000000000",
  "received": true,
  "provider_transaction_type": "string",
  "correlation": "charge_matched",
  "wallet_credited": true,
  "devolutions": [
    {
      "devolution_id": "devolution_0000000000000000",
      "status": "string",
      "amount_minor": 1000
    }
  ],
  "status_message": "string"
}

Example request

curl -X GET https://api.codespar.dev/v1/consumers/{consumerId}/pix/receivements/{endToEndId} \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/consumers/{consumerId}/receipts

A consumer's agentic receipts

Path parameters

NameTypeRequiredDescription
consumerIdstringyes

Responses

StatusBodyDescription
200objectOK

Response 200

FieldTypeRequiredDescription
receiptsarray of objectyes

Example response

{
  "receipts": [
    {
      "receipt_id": "receipt_0000000000000000",
      "state": "paid",
      "mandate": {
        "id": "obj_0000000000000000",
        "nonce": "string",
        "scope": "string",
        "currency": "BRL",
        "sig": "string"
      },
      "quote": {},
      "payment": {
        "rail": "string",
        "amount_minor": 1000,
        "amount_authorized": "1000",
        "amount_charged": "1000",
        "amount_refunded": "1000",
        "metering": {
          "basis": "string",
          "units": "string",
          "unit_price": "string"
        },
        "sandbox": true,
        "attempt_id": "attempt_0000000000000000",
        "money_moved": true,
        "at": "string"
      },
      "delivery": {
        "result": "confirmed"
      },
      "chain": "string",
      "receipt_sig": "string",
      "exceptions": [
        {
          "code": "string",
          "detail": "string",
          "at": "string"
        }
      ]
    }
  ]
}

Example request

curl -X GET https://api.codespar.dev/v1/consumers/{consumerId}/receipts \
  -H "Authorization: Bearer $CODESPAR_API_KEY"

GET /v1/consumers/{id}

Read one titular, with the ids of what hangs off it

Responses

StatusBodyDescription
200objectOK
404objectNot Found

Response 200

FieldTypeRequiredDescription
created_atstringyes
display_namestring,nullyes
documentstring,nullyes
document_sourcestring,nullyes
document_verified_atstring,nullyes
idstringyes
metadataobjectyes
person_typestring,nullyes
status"unverified" | "verified"yes
tax_typestring,nullyes

Example response

{
  "id": "obj_0000000000000000",
  "metadata": {},
  "status": "unverified",
  "created_at": "string"
}

Example request

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

PATCH /v1/consumers/{id}

Update the mutable fields of a titular

Request body

FieldTypeRequiredDescription
display_namestring,nullno
metadataobjectno
tax_type"PJ" | "MEI" | "ME" | "PF"no

Responses

StatusBodyDescription
200objectOK
400objectBad Request — the body or query did not match the schema.
404objectNot Found

Response 200

FieldTypeRequiredDescription
created_atstringyes
display_namestring,nullyes
documentstring,nullyes
document_sourcestring,nullyes
document_verified_atstring,nullyes
idstringyes
metadataobjectyes
person_typestring,nullyes
status"unverified" | "verified"yes
tax_typestring,nullyes

Example response

{
  "id": "obj_0000000000000000",
  "metadata": {},
  "status": "unverified",
  "created_at": "string"
}

Example request

curl -X PATCH https://api.codespar.dev/v1/consumers/{id} \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "metadata": {},
       "tax_type": "PJ"
     }'

GET /v1/consumers/{id}/wallet

The consumer's unified wallet, rolled up per currency

Path parameters

NameTypeRequiredDescription
idstringyes

Responses

StatusBodyDescription
200objectOK

Response 200

FieldTypeRequiredDescription
consumer_idstringyes
currenciesarray of objectyes

Example response

{
  "consumer_id": "csm_0000000000000000",
  "currencies": [
    {
      "currency": "BRL",
      "authorized_minor": 1,
      "spent_minor": 1,
      "available_minor": 1,
      "funding_source_ids": [
        "string"
      ],
      "mandate_ids": [
        "string"
      ]
    }
  ]
}

Example request

curl -X GET https://api.codespar.dev/v1/consumers/{id}/wallet \
  -H "Authorization: Bearer $CODESPAR_API_KEY"
Consumers | CodeSpar