Skip to main content
CBPay exposes card dispute and fraud-case information to the account that owns the payment. The account can read the case, follow the append-only timeline, upload evidence and download the evidence pack generated by the organization. Only organization administrators can open, submit or resolve a case.
The account API is read-only for case decisions. A successful upload does not change the decision; it adds an immutable evidence version to the case.

Evidence pack contents

When an organization generates an evidence pack, the account can download the same authenticated, private PDF associated with the case. It contains typed payin fields, ledger/FIFO evidence and external spend references. For card payins, the pack includes the processor-facing card operation (transaction references, approval, amount/currency/date, masked card details, issuer/country, 3DS, AVS/CVV, decision-manager result, device fingerprint and masked payer context). FIFO spends include the withdrawal or payout ID, asset/currency, status, destination address or bank reference and transaction hash when available. The merchant’s verified KYB/KYC identity is included in full for processor representation; the payer remains masked. Raw payin payloads and PAN-adjacent fields are excluded.

Open cases by identifiers

Organization administrators can open several cases from a pasted list of identifiers. This workflow accepts 1–100 unique, non-empty values after trimming and de-duplicating exact repeats. An identifier can be a payin ID, an idempotency key, a short reference, a qbank_reference or a qbank_payin_id. Both calls require the organization disputes:write permission. Preview is read-only: it does not create a case, hold funds or send a webhook.

1. Preview the list

The response separates exact matches from values that cannot resolve to one payin. An ambiguous value includes up to five candidates; the candidate contains payin_id, currency, local_amount and credited_at.
Preview matches can still show a payin that is not eligible to open yet. Use status and has_open_case before confirming: batch-open only opens credited payins without an open case. Single-case opening and manual import-row binding are also credited-only operations. A non-credited payin returns 409 payin_not_credited and creates no hold; batch and import workflows report the condition per item or row instead of failing the whole request.

2. Confirm the opening

Send the same identifiers, or the full pasted list, with one batch idempotency key. kind defaults to dispute and can also be fraud_hold.
The server resolves every identifier again. It never trusts a payin or account ID supplied by the client. Each matched credited payin is opened with its own idempotent key derived from the batch key and payin ID.
The batch response is 200 after the request is valid. case_already_open, not_found, ambiguous and not_credited are item-level skipped results; an amount or opening failure is an item-level failed result. Replaying the same batch key returns the original item as opened with idempotency_hit: true and does not create a second hold. The API returns invalid_payload for an empty list, empty values, an invalid kind or more than 100 unique identifiers. There is no separate top-level too_many response code. Missing idempotency returns idempotency_key_required; a missing organization scope returns org_required.

Lifecycle

An expired case keeps its preventive hold. Expiration is an operational signal, not an automatic money movement.

List your cases

The account scope is applied server-side. Supported filters are status and kind; from and to are inclusive organization dates.

Read one case

The detail adds the linked payins, append-only timeline and evidence metadata. Evidence content is never inlined in JSON.

Evidence

List evidence versions:
Upload one PDF, PNG or JPG (maximum 10 MB). The request body is multipart with the field name file:
Download a version as the original binary:
The response is authenticated binary content with its stored content type. Do not expose the URL without the account authorization header.

Webhook

Subscribe to dispute_status_changed through the normal webhook flow. The payload is account-scoped and contains the neutral case state:
Deduplicate deliveries by the webhook event ID. The event reports a state change; it never approves or rejects a case for the account.

Errors

See the error catalog for the common response envelope.

FAQ

No. Decisions are organization-admin actions protected by disputes:write and maker-checker rules.
No. The deadline worker only changes the case to expired and records an event. An administrator must make the explicit decision.
Yes. open, evidence and submitted accept account evidence. Won, lost and expired cases are closed to account uploads.

Locally held fiat

Disputes require a supported USDT credit. A payin with credit_asset BOB, MXN or ARS returns 409 dispute_fiat_unsupported without creating a case or hold. Batch-open skips it as fiat_unsupported; imports mark it unmatched as payin holds local fiat (unsupported).

USD as the principal ledger asset

Accounts use USD as the default for settlement_asset and payin_settlement_asset; change it any time with PUT /v1/settlement. In-flight operations are never re-quoted. USD ledger amounts use cents (two decimal places). Direct credits and debits, fees, and supported payout, checkout, POS, and card paths use USD only where their asset field accepts it. Swaps between USD and USDT use 1:1 pricing and do not use an FX oracle. BOB, MXN, and ARS remain separate fiat-ledger assets; v1 money-out pricing for those assets remains unavailable. A payin credited directly to a USD-principal account exposes credit_asset: USD and the credited fiat amount in cents; usdt_credited remains the USD-equivalent reporting field. A controversy hold follows the credited asset: USD credits use hold_asset: USD. disputed and held use hold-asset units; disputed_usdt and held_usdt are normalized equivalents.
Last modified on October 4, 2026