Credit exposure ( credit_exposure )

A credit_exposure measures credit currently granted and consumed by a buyer with a merchant. It is the counterpart of the credit limit : the limit sets the authorized ceiling, while exposure tracks what is actually committed.

Role

Where the receivable receivable aggregates existing invoices to answer “how much does this buyer owe me?”, the credit_exposure exposure answers “how much credit have I granted this buyer, and how much remains open?”.

Exposure is a persisted object — unlike receivable, it is not recalculated from invoices. It is built explicitly by orchestration processes, movement by movement, through an immutable ledger. This lets it cover flows that do not yet have an issued invoice, such as credit authorization or financing an order in progress, or that involve a financing company.

There is at most one exposure per tuple (buyer_id, merchant_id, currency).

Identifier and structure

Each exposure has a stable identifier prefixed with cex_. Every ledger movement uses prefix cem_.

JSON
"credit_exposure":{24 items
"object":"credit_exposure"
"id":"cex_2b4d1f8a9c3e7f5b"
"buyer_id":"cmp_3a8f1d9c2b4e7f6a"
"merchant_id":"mer_1a2b3c4d5e6f7a8b"
"currency":"eur"
"status":"active"
"authorized_amount_excluding_tax":500000
"authorized_amount_including_tax":600000
"consumed_amount_excluding_tax":100000
"consumed_amount_including_tax":120000
"released_amount_excluding_tax":0
"released_amount_including_tax":0
"settled_amount_excluding_tax":83334
"settled_amount_including_tax":100000
"cancelled_amount_excluding_tax":0
"cancelled_amount_including_tax":0
"expired_amount_excluding_tax":0
"expired_amount_including_tax":0
"outstanding_amount_excluding_tax":416666
"outstanding_amount_including_tax":500000
"movements":[2 items
0:{...}7 items
1:{...}7 items
]
"metadata":{}0 items
"created_at":"2026-06-17T10:00:00.000Z"
"updated_at":"2026-06-18T09:15:00.000Z"
}
{
"object": "credit_exposure",
"id": "cex_2b4d1f8a9c3e7f5b",
"buyer_id": "cmp_3a8f1d9c2b4e7f6a",
"merchant_id": "mer_1a2b3c4d5e6f7a8b",
"currency": "eur",
"status": "active",
"authorized_amount_excluding_tax": 500000,
"authorized_amount_including_tax": 600000,
"consumed_amount_excluding_tax": 100000,
"consumed_amount_including_tax": 120000,
"released_amount_excluding_tax": 0,
"released_amount_including_tax": 0,
"settled_amount_excluding_tax": 83334,
"settled_amount_including_tax": 100000,
"cancelled_amount_excluding_tax": 0,
"cancelled_amount_including_tax": 0,
"expired_amount_excluding_tax": 0,
"expired_amount_including_tax": 0,
"outstanding_amount_excluding_tax": 416666,
"outstanding_amount_including_tax": 500000,
"movements": [
  {
    "id": "cem_1a2b3c4d5e6f7a8b",
    "type": "credit_granted",
    "amount_excluding_tax": 500000,
    "amount_including_tax": 600000,
    "source_type": "checkout_session",
    "source_id": "cs_5e2d8f1a9b3c4d7e",
    "created_at": "2026-06-17T10:00:00.000Z"
  },
  {
    "id": "cem_9f2e1a4b3c8d7e6f",
    "type": "credit_settled",
    "amount_excluding_tax": 83334,
    "amount_including_tax": 100000,
    "source_type": "payment",
    "source_id": "pay_4a7b2e9f1c3d8a5e",
    "created_at": "2026-06-18T09:15:00.000Z"
  }
],
"metadata": {},
"created_at": "2026-06-17T10:00:00.000Z",
"updated_at": "2026-06-18T09:15:00.000Z"
}

Fields

FieldTypeDescription
idstringExposure identifier (prefix `cex_`).
objectstringAlways "credit_exposure".
buyer_idstringBuyer company (`cmp_…`).
merchant_idstringMerchant.
currencystringISO 4217 currency in lowercase (for example `eur`). Together with (`buyer_id`, `merchant_id`) it forms the unique key.
statusenum`active` or `closed`.
basisenumBasis used by the `amount` projection: `excluding_tax` or `including_tax`.
amountintegerAggregated outstanding balance on the basis selected by `basis`; practical projection of `outstanding_amount_excluding_tax` or `outstanding_amount_including_tax`.
authorized_amount_excluding_taxintegerTotal credit granted (excluding tax).
authorized_amount_including_taxintegerTotal credit granted (including tax).
consumed_amount_excluding_taxintegerIndicative consumed amount (excluding tax). Does not affect outstanding balance.
consumed_amount_including_taxintegerIndicative consumed amount (including tax).
released_amount_excluding_taxintegerReleased portion (excluding tax). Reduces outstanding balance.
released_amount_including_taxintegerReleased portion (including tax).
settled_amount_excluding_taxintegerAmount settled after payment (excluding tax). Reduces outstanding balance.
settled_amount_including_taxintegerSettled amount (including tax).
cancelled_amount_excluding_taxintegerCanceled amount (excluding tax). Reduces outstanding balance.
cancelled_amount_including_taxintegerCanceled amount (including tax).
expired_amount_excluding_taxintegerExpired amount (excluding tax). Reduces outstanding balance.
expired_amount_including_taxintegerExpired amount (including tax).
outstanding_amount_excluding_taxintegerActive outstanding balance (excluding tax). Computed field — see formula.
outstanding_amount_including_taxintegerActive outstanding balance (including tax). Computed field.
movementsarrayImmutable movement ledger (`cem_…` objects). See the Movements section.
metadataobjectFlat map of `string | number | boolean` scalars, following the API metadata convention.
created_atdatetimeCreation date.
updated_atdatetimeLast update date.

Amount counters

Exposure accumulates six pairs of counters (excluding tax + including tax). Each action on exposure increments one counter and may reduce active outstanding balance.

Action APICreated movementAffected counterEffect on outstanding balance
grantcredit_grantedauthorized ↑outstanding ↑
consumecredit_consumedconsumed ↑unchanged
releasecredit_releasedreleased ↑outstanding ↓
settlecredit_settledsettled ↑outstanding ↓
cancelcredit_cancelledcancelled ↑outstanding ↓
expirecredit_expiredexpired ↑outstanding ↓

Active outstanding balance (outstanding_amount_*) is calculated in real time:

text
outstanding = max(0, authorized − released − settled − cancelled − expired)
consume does not affect outstanding balance

The credit_consumed movement is purely indicative — it records that authorized credit was used, for example that an invoice was issued, but it does not reduce outstanding. Only release, settle, cancel and expire reduce active outstanding balance.

Each counter and the field outstanding exist on two bases (_excluding_tax and _including_tax). At least one basis must be provided for an action.

Movement ledger

The field movements is an append-only ledger — every action on exposure creates an immutable movement. It is the complete history of credit granted to this buyer.

Movement fieldDescription
idUnique movement identifier (prefix cem_).
typeMovement type: credit_granted, credit_consumed, credit_released, credit_settled, credit_cancelled, credit_expired.
amount_excluding_taxMovement amount excluding tax in cents. Optional depending on type.
amount_including_taxMovement amount including tax in cents. Optional depending on type.
source_typeType of source object for the movement, for example checkout_session, payment, or invoice.
source_idIdentifier of the source object.
reasonFree-form textual reason. Optional.
metadataFlat map of string | number | boolean scalars. Optional.
created_atMovement timestamp.

Status

StatusMeaning
activeExposure is open and can receive new movements.
closedExposure is closed (outstanding = 0 or total cancellation).

Interaction with the credit limit

The credit limit defines the authorized ceiling; exposure tracks what is actually committed. Available credit is the difference between the two.

text
available = credit_limit.effective_amount − credit_exposure.outstanding_amount

The nodes credit.evaluate_credit_availability and credit.check_credit_availability automatically calculate this comparison and produce an object credit_availability_check with the following fields:

JSON
"credit_availability_check":{11 items
"object":"credit_availability_check"
"decision":"approved"
"reason":"within_limit"
"basis":"excluding_tax"
"currency":"eur"
"limit_amount":500000
"used_amount":416666
"requested_amount":50000
"available_amount":83334
"projected_used_amount":466666
"projected_available_amount":33334
}
{
"object": "credit_availability_check",
"decision": "approved",
"reason": "within_limit",
"basis": "excluding_tax",
"currency": "eur",
"limit_amount": 500000,
"used_amount": 416666,
"requested_amount": 50000,
"available_amount": 83334,
"projected_used_amount": 466666,
"projected_available_amount": 33334
}

When decision is rejected, the reason is insufficient_available_credit. The process then routes to a decline path or request for additional collateral.

Shared lookup key

Credit limit and exposure share the same key (buyer_id, merchant_id, currency). The node credit.evaluate_credit_availability resolves both in one call.

In processes

Exposure is entirely driven by process nodes — there is no automatic update triggered by other objects.

NodeTypeDescription
credit.evaluate_credit_availabilityRouteurConsolidated node: resolves the effective limit, retrieves current exposure, and decides whether the requested amount is available. Outputs: `effective_credit_limit`, `credit_exposure`, `credit_availability_check`. Routes: `approved` / `rejected`.
credit.check_credit_availabilityRouteurChecks only capacity from already-loaded objects (`effective_credit_limit` + `credit_exposure` + `requested_amount`). Routes: `approved` / `rejected`.
credit.grant_creditHelperIncreases a company's authorized outstanding exposure (POST /grant). Accepts an optional `credit_availability_check` — fails when `decision=rejected`.
credit.fetch_credit_exposureHelperRetrieves a company's current exposure (GET /current). Returns an empty exposure (`outstanding = 0`) when none exists yet.
credit.consume_credit_exposureHelperRecords an indicative consumption (POST /consume). Does not affect outstanding balance.
credit.release_credit_exposureHelperReleases an unused portion (POST /release). Reduces outstanding exposure.
credit.settle_credit_exposureHelperSettles a portion after payment (POST /settle). Reduces outstanding exposure.
credit.cancel_credit_exposureHelperCancels all or part of the remaining exposure (POST /cancel). When no amount is supplied, cancels the full amount.

Typical flow: credit authorization

Here is the common shape of a credit-decision process during checkout:

text
credit.evaluate_credit_availability (company, requested amount)
→ approved → credit.grant_credit → create checkout session / order
→ rejected → notify buyer or request collateral

Typical flow: close after payment

text
payment.matched or psp_payment.succeeded
→ credit.fetch_credit_exposure (company)
→ credit.settle_credit_exposure (received amount)
→ [if outstanding = 0] credit.cancel_credit_exposure

Events

Every exposure action emits a distinct event. The payload includes the complete exposure state before and after the movement, plus the movement itself in latest_movement.

EventTrigger
credit_exposure.grantedPOST /grant — new outstanding exposure granted or existing exposure increased.
credit_exposure.consumedPOST /:id/consume — indicative consumption recorded.
credit_exposure.releasedPOST /:id/release — released portion.
credit_exposure.settledPOST /:id/settle — settled portion.
credit_exposure.cancelledPOST /:id/cancel — canceled portion.
credit_exposure.expiredPOST /:id/expire — expired portion.

The event credit_exposure.granted is emitted both at creation (first action grant) and on every subsequent increase in authorized outstanding balance.