Skip to main content
API reference

OFB

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

12 min read
View MarkdownEdit on GitHub

OFB

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/ofb/consents

Initiate a bank consent

Request body

FieldTypeRequiredDescription
bank_idstringyes
consumer_idstringyes
redirect_urlstring (uri)yesWhere the bank returns the consumer after authorisation. You compose it and you host it.
scopesarray of stringyes
wallet_idstringnoBinds the consent to a wallet, so the statements it ingests carry that wallet.

Responses

StatusBodyDescription
201objectCreated. The consent is pending and authorisation_url is set.
400objectThe body did not match the schema. details.issues carries the Zod issues.
409objectbank_consent_held_elsewhere when another project in this organization holds an open (pending or authorised) consent for this consumer at this bank. details.remediation says what to do and details.retriable is false: one project's bank grant is never shared with another, so re-sending this request unchanged will not clear it. consent_active_for_consumer when YOUR OWN project already holds one. Revoke it first. db_error when the consent could not be persisted for any other reason. The cause is in our logs under the request id and is deliberately not in this body, because the driver's own message names another project's key values.
500objectconsent_disappeared: the row was written and could not be read back. Do not retry blind; both the row and the bank-side consent may exist.
502objectThe bank refused the request or could not be reached, before anything was written. The message is the adapter's own.
503objectconsent_lock_timeout: another request is issuing a consent for this consumer at this bank and the wait ended without an answer, so NOTHING WAS DECIDED. We do not know whether a sibling holds the grant, and saying so is why this is not the 409. details.retriable is true. No consent row was created; a bank-side consent was, and is orphaned.

Response 201

FieldTypeRequiredDescription
authorisation_urlstring,nullyesWhere the consumer authorises the consent. This is the URL to send them to.
authorized_atstring,null (date-time)yesSpelled with a z, unlike authorised in status. Both spellings are column names, not typos.
bank_consent_idstring,nullyesThe bank's own identifier for the consent. Null until the bank issues one.
bank_idstringyesLowercase kebab-case, for example itau or bb.
consumed_atstring,null (date-time)yes
consumer_idstringyes
created_atstring (date-time)yes
expires_atstring,null (date-time)yesMirrors the bank-side consent expiry, as the bank reported it at initiation.
idstringyes
metadataobjectyes
revoked_atstring,null (date-time)yes
scopesarray of stringyes
status"pending" | "authorised" | "revoked" | "expired" | "consumed"yes
token_expires_atstring,null (date-time)yes
wallet_idstring,nullyesSet when the consent was bound to a wallet at initiation; null when it was not.

Example response

{
  "id": "obj_0000000000000000",
  "bank_id": "bank_0000000000000000",
  "consumer_id": "csm_0000000000000000",
  "status": "pending",
  "scopes": [
    "string"
  ],
  "created_at": "2026-01-15T12:00:00.000Z",
  "metadata": {}
}

Example request

curl -X POST https://api.codespar.dev/v1/ofb/consents \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "bank_id": "bank_0000000000000000",
       "consumer_id": "csm_0000000000000000",
       "scopes": [
         "string"
       ],
       "redirect_url": "https://example.com/hook",
       "wallet_id": "wlt_0000000000000000"
     }'

GET /v1/ofb/consents/{id}

Read one bank consent

Path parameters

NameTypeRequiredDescription
idstringyesofb_-prefixed consent id.

Responses

StatusBodyDescription
200objectOK
404objectNot Found. No consent with this id in the caller's project. A consent belonging to another project in the same organization answers here too.

Response 200

FieldTypeRequiredDescription
authorisation_urlstring,nullyesThe URL the consumer opens to authorise the consent at their bank.
authorized_atstring,null (date-time)yesAmerican spelling here, unlike status: "authorised"; both mirror their own column names. Stamped in the same statement as the transition into authorised.
bank_consent_idstring,nullyesThe bank's own identifier for the consent, as returned when it was opened.
bank_idstringyesLowercase kebab-case, as supplied when the consent was opened: itau, bradesco, bb, inter.
consumed_atstring,null (date-time)yes
consumer_idstringyesThe consumer, in the caller's own namespace.
created_atstring (date-time)yes
expires_atstring,null (date-time)yesMirror of the bank-side consent expiry, stamped when the consent is opened.
idstringyesofb_-prefixed. The id every other operation in this family takes.
metadataobjectyes
revoked_atstring,null (date-time)yes
scopesarray of stringyesThe OFB scopes the consent was opened for.
status"pending" | "authorised" | "revoked" | "expired" | "consumed"yesauthorised carries the British spelling, which is the column's own and not a typo. revoked, expired and consumed are terminal: no transition leaves them. Read "is this consent usable now" from status being authorised, never from revoked_at being null.
token_expires_atstring,null (date-time)yesExpiry of the bank access token. The token references themselves are never returned by this API.
wallet_idstring,nullyesThe wallet named on the create request, or null. Written once at creation and never rewritten: neither state transition on this consent touches the column. It is a label, not routing. A statement refresh copies this value onto every event it ingests, and nothing downstream reads it: reconciliation resolves a wallet from the funding source behind an event's connection_id, and the events this family publishes carry no such key. Binding a consent to a wallet therefore does not, on its own, put the ingested statement into that wallet's reconciliation.

Example response

{
  "id": "obj_0000000000000000",
  "bank_id": "bank_0000000000000000",
  "consumer_id": "csm_0000000000000000",
  "status": "pending",
  "scopes": [
    "string"
  ],
  "created_at": "2026-01-15T12:00:00.000Z",
  "metadata": {}
}

Example request

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

POST /v1/ofb/consents/{id}/callback

Finalise a consent after the consumer authorises it

Path parameters

NameTypeRequiredDescription
idstringyes

Request body

FieldTypeRequiredDescription
auth_codestringyesThe code the bank put on the redirect.

Responses

StatusBodyDescription
200objectOK
400objectThe body did not match the schema. details.issues carries the Zod issues.
404objectNo such consent for this credential's organization AND project. A consent created by a sibling project in the same organization answers the same way: the resolver requires both predicates on purpose, because resolving on organization alone let one project read, transition and refresh another project's consent.
409objectThe consent's current status does not permit this transition. details.from and details.to carry the pair. pending may become authorised, revoked or expired; authorised may become revoked, expired or consumed; revoked, expired and consumed are terminal and permit nothing.
500objectmissing_bank_consent_id: the stored consent carries no bank-side id, so there is nothing to finalise. Ours to fix, not yours; quote the request id.
502objectThe bank refused the code or could not be reached. What this handler wrote is nothing: the UPDATE runs only after the exchange returns, so the consent is still pending and no token pointer was stored. Whether the code itself is still usable is the BANK's state and not ours to report, so this answer does not claim either way. The message is the adapter's own, and empty when what the adapter threw was not an Error.

Response 200

FieldTypeRequiredDescription
authorisation_urlstring,nullyesWhere the consumer authorises the consent. This is the URL to send them to.
authorized_atstring,null (date-time)yesSpelled with a z, unlike authorised in status. Both spellings are column names, not typos.
bank_consent_idstring,nullyesThe bank's own identifier for the consent. Null until the bank issues one.
bank_idstringyesLowercase kebab-case, for example itau or bb.
consumed_atstring,null (date-time)yes
consumer_idstringyes
created_atstring (date-time)yes
expires_atstring,null (date-time)yesMirrors the bank-side consent expiry, as the bank reported it at initiation.
idstringyes
metadataobjectyes
revoked_atstring,null (date-time)yes
scopesarray of stringyes
status"pending" | "authorised" | "revoked" | "expired" | "consumed"yes
token_expires_atstring,null (date-time)yes
wallet_idstring,nullyesSet when the consent was bound to a wallet at initiation; null when it was not.

Example response

{
  "id": "obj_0000000000000000",
  "bank_id": "bank_0000000000000000",
  "consumer_id": "csm_0000000000000000",
  "status": "pending",
  "scopes": [
    "string"
  ],
  "created_at": "2026-01-15T12:00:00.000Z",
  "metadata": {}
}

Example request

curl -X POST https://api.codespar.dev/v1/ofb/consents/{id}/callback \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "auth_code": "string"
     }'

POST /v1/ofb/consents/{id}/refresh-statement

Fetch the bank statement and ingest it

Path parameters

NameTypeRequiredDescription
idstringyes

Request body

FieldTypeRequiredDescription
sincestring (date-time)no
untilstring (date-time)no

Responses

StatusBodyDescription
202objectAccepted. The statement was fetched and ingested; reconciliation happens after.
400objectThe body did not match the schema: since and until must be RFC 3339 timestamps carrying an offset. details.issues carries the Zod issues.
404objectNo such consent for this credential's organization AND project. A consent created by a sibling project in the same organization answers the same way: the resolver requires both predicates on purpose, because resolving on organization alone let one project read, transition and refresh another project's consent.
409objectconsent_not_authorised: the consent is not in authorised. details.status carries what it is.
500objectconsent_missing_tokens: the consent says authorised but is missing something the fetch needs. TWO conditions raise it and the code does not distinguish them: no stored access-token pointer, OR no bank-side consent id. The second is not a token, so read the code as this authorised consent is not usable rather than as a statement about credentials. Ours to fix, not yours; quote the request id.
502objectThe bank refused or could not be reached. Partial progress is KEPT: each entry is committed as it is ingested, so entries taken before the failure stay ingested and a retry re-imports only what is missing. The message is the adapter's own unless the failure came from our own database, in which case it is replaced by a fixed sentence rather than naming our tables.

Response 202

FieldTypeRequiredDescription
consent_idstringyes
duplicatesintegeryesEntries a previous call had already ingested, recognised by the dedup key and not credited a second time.
importedintegeryesEntries ingested as new events by this call.
next_recon_cycle_within_secondsintegeryesA constant hint about how often reconciliation runs. Not a queue estimate and not a promise about this run.
run_idstringyesIdentifies this refresh in the consent's event log, on the started, completed and failed events alike. Quote it in support.

Example response

{
  "consent_id": "consent_0000000000000000",
  "run_id": "run_0000000000000000",
  "imported": 0,
  "duplicates": 0,
  "next_recon_cycle_within_seconds": 0
}

Example request

curl -X POST https://api.codespar.dev/v1/ofb/consents/{id}/refresh-statement \
  -H "Authorization: Bearer $CODESPAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "since": "2026-01-15T12:00:00.000Z",
       "until": "2026-01-15T12:00:00.000Z"
     }'

POST /v1/ofb/consents/{id}/revoke

Revoke a bank consent

Path parameters

NameTypeRequiredDescription
idstringyes

Request body

FieldTypeRequiredDescription
reasonstringnoRecorded on the revoked event.

Responses

StatusBodyDescription
200objectOK
400objectThe body did not match the schema. details.issues carries the Zod issues.
404objectNo such consent for this credential's organization AND project. A consent created by a sibling project in the same organization answers the same way: the resolver requires both predicates on purpose, because resolving on organization alone let one project read, transition and refresh another project's consent.
409objectThe consent's current status does not permit this transition. details.from and details.to carry the pair. pending may become authorised, revoked or expired; authorised may become revoked, expired or consumed; revoked, expired and consumed are terminal and permit nothing.

Response 200

FieldTypeRequiredDescription
authorisation_urlstring,nullyesWhere the consumer authorises the consent. This is the URL to send them to.
authorized_atstring,null (date-time)yesSpelled with a z, unlike authorised in status. Both spellings are column names, not typos.
bank_consent_idstring,nullyesThe bank's own identifier for the consent. Null until the bank issues one.
bank_idstringyesLowercase kebab-case, for example itau or bb.
consumed_atstring,null (date-time)yes
consumer_idstringyes
created_atstring (date-time)yes
expires_atstring,null (date-time)yesMirrors the bank-side consent expiry, as the bank reported it at initiation.
idstringyes
metadataobjectyes
revoked_atstring,null (date-time)yes
scopesarray of stringyes
status"pending" | "authorised" | "revoked" | "expired" | "consumed"yes
token_expires_atstring,null (date-time)yes
wallet_idstring,nullyesSet when the consent was bound to a wallet at initiation; null when it was not.

Example response

{
  "id": "obj_0000000000000000",
  "bank_id": "bank_0000000000000000",
  "consumer_id": "csm_0000000000000000",
  "status": "pending",
  "scopes": [
    "string"
  ],
  "created_at": "2026-01-15T12:00:00.000Z",
  "metadata": {}
}

Example request

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