Reciprocity

How the Cumbuca Gateway API fulfils the Open Finance reciprocity duty, answering other participants' lookups about your account holders, in its two operating modes: without delegation, where Cumbuca stores the records and answers for you, and with delegation, where every lookup is proxied live, over mTLS, to a service you run yourself.

What is Reciprocity

Participating in Open Finance Brasil as a data receiver comes with a reciprocity duty: other participants can ask whether a given document belongs to one of your account holders, and read that customer's identification records. Cumbuca fulfils this duty in one of two ways, decided by a single instance-wide setting, namely delegation.

With and without delegation

Without delegation (delegation off), the default. Cumbuca stores the customer records it knows about (through the automatic registration that follows an authorised consent, or through the PUT /personal/identifications/register and PUT /business/identifications/register writes) and answers ecosystem lookups itself, from its own store. Your service is not called.

OF ecosystem requesting institution Cumbuca store 1 account-holder / identification lookup 2 answered from its own store

With delegation (delegation on). Cumbuca stores nothing. Every reciprocity lookup is proxied live, over mTLS, to a service that you implement and operate. It becomes the source of truth.

OF ecosystem requesting institution Cumbuca gateway (stores nothing) YOUR service source of truth 1 account-holder / identification lookup 2 proxied live mTLS 3 response 4 forwarded (nothing stored)
Instance-wide, all-or-nothing. Delegation is a configuration of your whole Cumbuca instance, agreed at onboarding. It applies to every client of the tenant: you cannot delegate one client and keep another stored at Cumbuca.

Comparison

Without delegationWith delegation
Where customer data livesStored at CumbucaAt your service; nothing stored at Cumbuca
Who answers ecosystem lookupsCumbuca, from its own storeYour service, one live call per lookup
Automatic post-consent registrationPerformed (details)Skipped (details)
PUT /personal/identifications/register
PUT /business/identifications/register
201: record stored422: always refused (details)
Endpoints your service exposesNoneFour, plus three more if you serve PJ customers (contract)
Availability dependencyNone on your systemsAn outage of your service fails the tenant's reciprocity lookups (details)

Automatic Registration (without delegation)

When the instance does not delegate, Cumbuca itself needs to know your account holders in order to answer reciprocity lookups. It populates that store automatically, with no partner action, from the data-sharing consents your instance creates:

  1. When a data-sharing consent is created, Cumbuca starts tracking it.
  2. Open Finance does not push status changes, so Cumbuca polls the consent until it reaches AUTHORISED (or expires, when the ecosystem auto-rejects unauthorised consents after ~1 h).
  3. Once authorised, Cumbuca reads the customer's identifications through the consent (a billable read) and stores each record, with x-data-source: internal. A personal consent feeds /personal/identifications; a business consent (one carrying a businessEntity) feeds /business/identifications.

The two are independent: a consent that grants both permissions registers both, and a failure on one side never blocks the other.

Open Finance consent + read Cumbuca gateway Store at Cumbuca 1 consent created + CUSTOMERS_PERSONAL_IDENTIFICATIONS_READ 2 polls status until AUTHORISED 3 reads /personal/identifications (billable) 4 stores each record x-data-source: internal

Registration is idempotent, so re-runs are harmless. For personal records, data you write yourself (via PUT /personal/identifications/register, source tenant) takes precedence over the internal automatic registration and is never overwritten by it.

Business records have no precedence by origin. Unlike the personal store, the business store does not rank writes by source: whichever write lands last wins, whether it came from you or from the automatic registration. If you maintain PJ records yourself, expect an authorised business consent to refresh them.

Mandatory permissions

Automatic registration is only possible if the consent carries the permission that authorises Cumbuca to read the customer's identification data. That is why, when the instance does not delegate, Cumbuca adds the matching permission automatically at consent creation, ensuring the reciprocity store can be populated:

ConsentPermission added
Personal (no businessEntity)CUSTOMERS_PERSONAL_IDENTIFICATIONS_READ
Business (carries businessEntity)CUSTOMERS_BUSINESS_IDENTIFICATIONS_READ

Only the identifications permission is added. Qualification and financial-relations records are derived from the same identifications payload, so they need no separate read.

With Delegation: Your Service's Contract

When your instance delegates, you hand Cumbuca a base URL at onboarding. HTTPS is mandatory in production and homologation. Under that base URL, your service must implement the JSON POST endpoints below; the paths are relative to that base URL. The business (PJ) endpoints are only required if your institution serves legal-entity customers.

EndpointAnswers with
POST /check-account-holderbooleanrequired
POST /personal/identificationsarrayrequired
POST /personal/qualificationsobjectrequired
POST /personal/financial-relationsobjectrequired
POST /business/identificationsarrayPJ only
POST /business/qualificationsobjectPJ only
POST /business/financial-relationsobjectPJ only
Two response shapes. Identifications answer with a data array of records and use "data": [] for "nothing to report". Qualifications and financial-relations answer with a single data object, and signal "no record for this document" with an HTTP 404 instead (see below).
Request headers Cumbuca sends
HeaderValue
content-typeapplication/json
x-nexus-request-idUUIDv7 correlation id; log it and include it in support requests

POST/check-account-holder

The Cumbuca gateway asks whether the given document belongs to an account holder at your institution. This is an integration requirement, not the reciprocity data itself: it is an account-holder (titularidade) check the flow depends on, distinct from the identification endpoints below, which return the registration data actually shared under reciprocity. Your service must expose it to operate in Open Finance.

Request body (sent by Cumbuca)
{
  "cpf": "12345678901",
  "cnpj": "12345678000199" // optional
}
Body fields
FieldTypeNotes
cpfstringrequired The logged user's 11-digit CPF (the natural person; for a legal entity, the representative's CPF)
cnpjstringoptional The legal-entity document, present only when it accompanies the consent; always 14 digits
The legal-entity document arrives in the cnpj field. The cpf field is always the logged user's 11-digit CPF; the CNPJ, when present, comes in the cnpj field (14 digits).
Required response (200)
{
  "data": { "isAccountHolder": true }
}

data.isAccountHolder must be a JSON boolean. A 200 whose body is not JSON, or whose data.isAccountHolder is missing or not a boolean, is treated as a failed lookup; extra fields are ignored (see error mapping).

POST/personal/identifications

Cumbuca fetches the natural person's Open Finance personal-identifications records from your service.

Request body (sent by Cumbuca)
{
  "cpf": "12345678901"
}
Required response (200)
{
  "data": [
    { /* Open Finance Brasil personal-identifications record */ }
  ]
}

A JSON object with a data array. Each element must already be a valid Open Finance Brasil personal-identifications record; Cumbuca serves the array to the requesting institution verbatim, wrapped only with meta.requestDateTime. Return "data": [] when there is nothing to report.

POST/business/identificationsoptional

Cumbuca fetches the legal entity's Open Finance business-identifications records from your service. Required only if your institution serves legal-entity (PJ) customers; institutions that serve natural persons only do not need to expose it.

Request body (sent by Cumbuca)
{
  "cnpj": "12345678000199"
}
Required response (200)
{
  "data": [
    { /* Open Finance Brasil business-identifications record */ }
  ]
}

Same semantics as /personal/identifications: a JSON object with a data array of OF Brasil business-identifications records, served verbatim to the requesting institution.

POSTQualifications & financial relations

Four endpoints sharing one contract. Cumbuca fetches the customer's Open Finance qualification or financial-relations data from your service. Unlike identifications, each answers with a single object, not an array.

PathBody field
/personal/qualificationscpfrequired
/personal/financial-relationscpfrequired
/business/qualificationscnpjPJ only
/business/financial-relationscnpjPJ only
Request body (sent by Cumbuca)
{
  "cpf": "12345678901"    // "cnpj" on the business paths
}
Required response (200)
{
  "data": { /* Open Finance Brasil qualification / financial-relations object */ }
}

data must be a JSON object, not an array. Cumbuca serves it to the requesting institution verbatim, wrapped only with meta.requestDateTime. A 200 whose data is an array or absent fails the lookup.

Return 404 when you have no record for the document. There is no empty-object equivalent of "data": [] here. Cumbuca recognises your 404 as "unknown document" and answers the requesting institution with 404, which is exactly what a non-delegated instance returns for a document it has never registered. Any other failure is treated as an outage on your side.

mTLS on the Delegated Leg

Every call from Cumbuca to your service rides on mutual TLS. There is no bearer token and no API key on this hop: the gateway's client certificate is the only authentication.

Timeout Budget

Failure Semantics

Operational consequence: while your service is unavailable, reciprocity lookups against your tenant fail until it recovers. That includes account-holder checks, identification reads, and qualification / financial-relations reads. Consent creation and the rest of your receiver-side flows keep working normally: they do not go through your delegated service.

Error mapping

What each behaviour of your service produces downstream:

Your service's behaviourCumbuca gateway resultWhat the requesting institution sees
200 with the exact documented shape200 data forwarded200 with the data
Non-200 statusSame status, code DELEGATED_ERROR ("the delegated client returned an error"); your body withheld500 INTERNAL_SERVER_ERROR
Timeout (> 30 s), connection refused, TLS failure502 DELEGATED_UNAVAILABLE ("the delegated client is unavailable")500 INTERNAL_SERVER_ERROR
200 with a non-JSON body or wrong shape502 DELEGATED_UNAVAILABLE500 INTERNAL_SERVER_ERROR
200 JSON object without a data array (identifications)Passes the gateway, rejected downstream500 INTERNAL_SERVER_ERROR
404 on qualifications / financial-relations404: recognised as "no record for this document"404, same as a non-delegated instance

What Changes When You Delegate

Registration returns 422

On a delegated instance, both partner-facing registration writes, PUT /personal/identifications/register and PUT /business/identifications/register, are always refused: every authenticated, well-formed request gets 422 and nothing is ever stored (malformed bodies still get the generic 400/415, and missing auth gets 401):

HTTP/1.1 422
x-nexus-error-source: client
x-nexus-request-id: <uuidv7>

{
  "errors": [
    {
      "code": "UNKNOWN",
      "title": "Unknown Error",
      "detail": "Registration not supported for a delegated client"
    }
  ],
  "meta": { "requestDateTime": "2026-07-15T12:00:00Z" }
}

Don't call registration on a delegated instance; treat this 422 as the expected, permanent answer.

The automatic registration that populates Cumbuca's store does not apply when you delegate. After a data-sharing consent reaches AUTHORISED, Cumbuca still attempts the internal write, for personal and business alike, but it is refused with the same 422 (nothing is stored at Cumbuca) and the step is silently skipped. Your service is the only place reciprocity data comes from. Cumbuca also skips adding the identifications permission to consents on a delegated instance, since it never needs to perform that read.

LGPD - nothing stored at Cumbuca

With delegation enabled, no customer identification data for reciprocity is retained at Cumbuca: registration writes are refused before validation, and every read is answered live from your service. Personal data handled for reciprocity stays inside your infrastructure.


Cumbuca Gateway API - Reciprocity.