Skip to main content

Bridge — Webhooks, API Mechanics & Issuance

What this covers / who it's for. A durable, dated digest of Bridge's webhook system (event structure, signature scheme, delivery/retry/ordering, endpoint lifecycle), core API mechanics (auth, idempotency, pagination, precision, deprecation, sandbox), receipts/pricing, stablecoin issuance (mint/burn, reserves, transparency, rewards, USDB), and the recent changelog — for engineers building or reviewing anything that talks to Bridge from this repo. Facts reflect apidocs.bridge.xyz as fetched on 2026-09-03; re-verify any claim via the bridge-development skill's protocol (llms.txt → matching .md page, cite + date) and check changelog/changelog.md before trusting a number here — this is a snapshot, not a live mirror. Nothing here is live traffic in Stables today: BridgeRailsProvider (D118) is registered but not granted, and the bridge webhook source is verified/deduped/stored but has no domain handlers wired as of this fetch — see "Implications for Stables" per section for what applies once (or if) it goes live.

1. Page index

All URLs are apidocs.bridge.xyz paths, fetched 2026-09-03.

PageURLCovers
Webhooks overviewplatform/additional-information/webhooks/overview.mdEndpoint requirements, implementation flow, disabled/active/deleted, retry FAQ
Signature verificationplatform/additional-information/webhooks/signature.mdX-Webhook-Signature header, SHA-256 over t.body, per-endpoint PEM, 10-min window
Event structureplatform/additional-information/webhooks/structure.mdCategories, mutations, envelope schema, JSON examples
Create/update/delete/list webhook endpointapi-reference/webhooks/*.mdPOST/PUT/DELETE/GET /v0/webhooks[/{id}]
List upcoming events / send event / view logsapi-reference/webhooks/list-upcoming-events.md, send-event.md, view-logs.mdPer-endpoint queue, manual redeliver, delivery log
List webhook eventsapi-reference/webhooks/list-webhook-events.mdGET /v0/webhook_events — account-wide replay primitive
Setting up webhooks (guide)get-started/introduction/quick-start/setting-up-webhooks.md4-step create→verify→test→enable; sample verifiers (Python/Node/Ruby/Java/Go)
Authenticationapi-reference/introduction/introduction.mdApi-Key header, base URLs, 401 shape
Idempotencyapi-reference/introduction/idempotence.mdIdempotency-Key, 24h window, 422 after
Deprecationapi-reference/introduction/deprecation.mdDeprecated ≠ removed, changelog as the notice channel
Paginationapi-reference/pagination.mdCursor pagination, starting_after/ending_before
Precision and roundingplatform/additional-information/precision.mdWhole-cent truncation, fee round-up, Input = Output / 0.999
Pricingplatform/additional-information/pricing.md"Contact sales@bridge.xyz"
Receiptsplatform/additional-information/receipts.mdBridge-sent receipts, receipt.url
Sandbox (simulate KYC approval)api-reference/sandbox/simulate-kyc-approval-sandbox-only.mdSandbox-only KYC approval simulation
Sandbox integration (wallets)platform/wallets/sandbox.mdFake addresses, simulate_deposit
Issuance overviewplatform/issuance/overview.md4-step model: orchestration → minting → reserves → rewards
Issuance optionsplatform/issuance/issuance-options.mdOUSD vs Open Issuance vs USDB
USDBplatform/issuance/usdb.mdBridge's closed-loop coin
Designing your stablecoinplatform/issuance/designing-your-stablecoin.mdOnboarding inputs, supported chains
Minting and burningplatform/issuance/minting-and-burning.mdNo mint/burn API — automatic side effect of transfers
Reserve managementplatform/issuance/reserve-management.mdLiquidity split, reward rates, /v0/issuance/reserves/liquidity_allocation
Reporting and transparencyplatform/issuance/reporting-and-transparency.mdAttestations, transparency.bridge.xyz public API
Earning rewardsplatform/issuance/rewards.mdEFFR-linked rate, payout by 5th business day, rewards history API
Growing your stablecoinplatform/issuance/growing-your-stablecoin.mdStripe distribution, DEX liquidity, CEX "coming soon"
Changelogchangelog/changelog.mdDated product/API updates

2. Webhooks — envelope, categories, tolerant parsing

Envelope fields

Every delivery: api_version (v0), event_id (wh_…, globally unique — the dedup key), event_developer_id, event_sequence (int, present in some examples, absent in others), event_category, event_type (<category>.<mutation>), event_object_id (= event_object.id), event_object_status (optional — populated only when the resource has a status field, e.g. kyc_status/transfer_status; null for VA/wallet-activity events, whose state lives in event_object.type instead), event_object (full resource, same rendering as the GET API), event_object_changes ({field: [old, new]} diff — {} on creates, and sometimes on updates too), event_created_at (ISO 8601). (platform/additional-information/webhooks/structure.md)

Categories and mutations

CategoryMutations
customercreated, updated, updated.status_transitioned, deleted
kyc_linkcreated, updated, updated.status_transitioned
liquidation_address.draincreated, updated, updated.status_transitioned
static_memo.activitycreated, updated
transfercreated, updated, updated.status_transitioned
virtual_account.activitycreated, updated
bridge_wallet.activitycreated, updated
card_accountcreated, updated, updated.status_transitioned
card_transactioncreated, updated, updated.status_transitioned
posted_card_account_transactioncreated
external_acccount (sic — triple "c" on the docs page)created, updated

Also named in the bullet list but absent from the table: card_withdrawal. OpenAPI's WebhookEventCategory enum additionally lists rfi (undocumented elsewhere) and spells the account category correctly: external_account. GET /v0/webhook_events?category= also accepts legacy values liquidation_address, virtual_account, shift4_base_deposit, indexed_deposit. The mutation enum additionally lists canceled.

external_acccount typo vs API enum external_account. The event-type table spells the category with three c's; OpenAPI's enum and the actual resource name are correct (external_account). No JSON webhook example exists for this category anywhere in the docs (only the retrieve-object schema) — verify the real field spelling against a live delivery before hard-coding either form.

Tolerant event_type parsing

Bridge's own docs disagree on whether event_type is bare or category-prefixed: the structure page's reference table lists bare mutations (created, updated.status_transitioned); its JSON examples are mixed — some transfer examples are bare ("created"), one is prefixed ("transfer.updated"), while customer/kyc_link/virtual_account.activity examples are consistently prefixed; the OpenAPI schema asserts values "will be prefixed with the event_category" — the canonical claim, contradicted by the table and some examples. Implication: parse tolerantly — prefix with event_category only when event_type doesn't already start with it (never double-prefix); never string-compare the raw field. See §5.

3. Signature scheme

Header: X-Webhook-Signature: t=<unix_ms>,v0=<base64 signature>. Verification: parse t/v0; build message "<t>.<raw body>" (raw request body bytes, no pre-JSON-decode); SHA-256 digest; strict-base64-decode v0; verify against the endpoint's public_key (per-endpoint PEM). The algorithm is not named on the signature page; the setup guide's sample code uses RSA PKCS#1 v1.5 with SHA-256. Replay tolerance: reject events older than "a few minutes, e.g. 10 minutes" and — per Bridge's own guidance — return 400 to request a retry. Key rotation is not documented. (platform/additional-information/webhooks/signature.md, get-started/introduction/quick-start/setting-up-webhooks.md)

Documented cross-language disagreement in Bridge's own sample verifiers. The setup guide's five sample verifiers disagree on the hashing step: Go explicitly double-hashes — sha256(sha256("t.body")) — then rsa.VerifyPKCS1v15(pub, crypto.SHA256, hashed); Python / Node / Java feed the single SHA-256 digest of "t.body" into a SHA256-with-RSA verify call, which itself hashes internally — an effective double hash, consistent with Go; Ruby verifies the un-digested raw payload directly against a SHA256-with-RSA verifier — a single hash, inconsistent with the other four. Stated plainly rather than resolved: BridgeSignatureValidator must be verified against a real production Bridge event before go-live — sandbox endpoints receive zero events (§4), so this cannot be tested pre-prod. PHP's openssl_verify() hashes internally given a digest algorithm — called here on the un-digested raw "<t>.<rawBody>" string, exactly as Ruby's sample verifier does — so this app's implementation (BridgeSignatureValidator, app-modules/webhooks/README.md:227-245) follows the single-hash net effect (Ruby, not Python/Node/Java/Go). Concretely: our implementation matches only 1 of Bridge's 5 sample conventions, which RAISES the go-live verification risk stated above — it must be verified against a real production delivery before go-live, not assumed correct by majority convention; unconfirmed against a live delivery.

Stale timestamp: Bridge suggests 400, this app returns 401. This app's bootstrap/app.php render callback maps every false SignatureValidator return (Bridge included) to HTTP 401 uniformly, for consistency with every other source — a deliberate, documented deviation, safe because Bridge retries any non-2xx response regardless of status code.

4. Delivery, retry, ordering, endpoint lifecycle, replay

Delivery: POST, application/json; endpoint should "return a 200 status … as quickly as possible to avoid timeouts and retries" — no specific timeout value documented.

Retry: "up to two days" of automatic exponential backoff on an unavailable endpoint; exact schedule/intervals not stated. Each retry carries a fresh timestamp in the signature header (not a byte-identical resend).

No ordering guarantee. Nothing promises in-order delivery. The only sequencing primitives are event_sequence (int, present in some envelope examples, absent in others) and GET /v0/webhook_events, stated to return results "ordered by their event_sequence in ascending order" — a pull-API guarantee, not a push-delivery one.

GET /v0/webhook_events as the replay primitive. Account-wide (not per-endpoint), last 90 days, ascending event_sequence, limit up to 500 (vs 100 elsewhere), filterable by category. Combined with per-endpoint GET /v0/webhooks/{id}/events (next 10 queued) and POST /v0/webhooks/{id}/send {event_id} (manual redeliver, "does not guarantee immediate delivery"), this is the recovery path after an outage past the two-day retry horizon, or after re-enabling an endpoint.

No backlog replay on re-enable, since 06/29/2026. Re-enabling a disabled endpoint no longer replays the backlog queued while disabled (changelog). Recovery is manual: list events via GET /v0/webhook_events filtered to the outage window, then send each one.

Endpoint lifecycle. Webhook: id (wep_…), url, status (active|disabled|deleted), public_key (per-endpoint PEM), event_categories[]. Created via POST /v0/webhooks (Idempotency-Key required): url HTTPS + valid X.509 ("doesn't need to be live, but the host must be reachable"); event_epoch = webhook_creation (a few events preceding creation, "for convenience") or beginning_of_time; starts disabled. Max 5 endpoints (active + disabled combined, per developer account). Updated via PUT /v0/webhooks/{id}url, status, event_categories (new categories deliver only from that point onward). A URL change requires disabling the endpoint first. Deleted via DELETEstatus: deleted, no longer accessible.

5. JSON samples (verbatim, ≤40 lines each)

customercustomer.created (fires at KYC-link creation, before any user action — status: not_started; client_reference_id: null here, populated later once we set it):

{
"api_version": "v0", "event_id": "wh_2tEL5NVw3dkEpLRJz4dS8gqWYX1", "event_sequence": 1,
"event_category": "customer", "event_type": "customer.created",
"event_object_id": "c_2tEKzQmNvR9xJfPdL8mY4hsBk3A", "event_object_status": "not_started",
"event_object": {
"id": "c_2tEKzQmNvR9xJfPdL8mY4hsBk3A", "first_name": "Jane", "last_name": "Doe",
"email": "jane.doe@example.com", "type": "individual", "status": "not_started",
"has_accepted_terms_of_service": false, "client_reference_id": null,
"tos_link": "https://dashboard.bridge.xyz/tos/c_2tEKzQmNvR9xJfPdL8mY4hsBk3A",
"rejection_reasons": [],
"endorsements": [{"name": "base", "status": "incomplete", "requirements": {"complete": [],
"pending": [], "missing": {"id_verification": "Identity verification required"}, "issues": []}}],
"created_at": "2025-11-19T21:14:58.328Z", "updated_at": "2025-11-19T21:14:58.328Z"
},
"event_object_changes": {}, "event_created_at": "2025-11-19T21:14:58.328Z"
}

kyc_linkkyc_link.updated.status_transitioned (customer_id: null even mid-transition — exact moment it populates, and whether it appears in event_object_changes, is undocumented):

{
"api_version": "v0", "event_id": "wh_tmyqyd9q5nsVJazfux9EiQC", "event_category": "kyc_link",
"event_type": "kyc_link.updated.status_transitioned",
"event_object_id": "3694522e-6bed-4660-a803-f599b50c7691", "event_object_status": "incomplete",
"event_object": {
"id": "3694522e-6bed-4660-a803-f599b50c7691", "type": "individual",
"email": "danyka+wintheiser@quigley.xyz", "kyc_link": "<KYC link>", "tos_link": "<ToS link>",
"full_name": "Danyka Wintheiser", "kyc_status": "incomplete", "tos_status": "approved",
"customer_id": null, "persona_inquiry_type": "gov_id_db"
},
"event_object_changes": {"kyc_status": ["not_started", "incomplete"],
"tos_status": ["pending", "approved"]},
"event_created_at": "2024-02-09T17:00:43.709Z"
}

transfercreated, status awaiting_funds (bare event_type — one of the pages' own inconsistent examples, see §2):

{
"api_version": "v0", "event_id": "wh_123abc456def", "event_category": "transfer",
"event_type": "created", "event_object_id": "tr_abc123xyz789",
"event_object_status": "awaiting_funds",
"event_object": {
"id": "tr_abc123xyz789", "state": "awaiting_funds", "amount": "1500.00", "currency": "usd",
"developer_fee": "0.0", "client_reference_id": null, "on_behalf_of": "cust_alice",
"source": {"currency": "usdc",
"from_address": "0x1111111111111111111111111111111111111111", "payment_rail": "polygon"},
"destination": {"currency": "usd", "payment_rail": "ach",
"external_account_id": "external-account-123"},
"receipt": {"gas_fee": "0.0", "exchange_fee": "0.0", "developer_fee": "0.0",
"initial_amount": "1500.00", "subtotal_amount": "1500.00", "final_amount": "1500.00"},
"created_at": "2025-07-22T11:26:55.000Z", "updated_at": "2025-07-22T11:26:56.000Z"
},
"event_object_changes": {}, "event_created_at": "2025-07-22T11:26:00.000Z"
}

Implications for Stables

The bridge webhook source (D118) is verified/deduped/stored today with no domain handlers wired — see app-modules/webhooks/README.md for what's actually built. Intended domain handlers (event type → module → command) are designed, not shipped, in the alignment design §3 — tenant resolution bootstraps by setting client_reference_id on every outbound kyc_links/customers/VA/transfer create call; provider_customers covers events carrying only customer_id. Go-live sequencing is recorded in D118 §Go-live and design §6/§7.

6. API mechanics

Authentication. Api-Key header on every request (the intro page calls this "HTTP Basic Auth" but the shown example is a bare header, not RFC 7617 Basic auth — wording inconsistency, not a different mechanism). HTTPS only. Missing/invalid key → 401 {code: required|invalid, location: "header", name: "Api-Key", message}. Sandbox keys are scoped per developer account, invisible to teammates. Scoped API keys (changelog 03/23/2026) add resource-level permissions, immutable after creation. Base URLs: https://api.bridge.xyz/v0 (prod), https://api.sandbox.bridge.xyz (sandbox) — the idempotency page's own example uses /v1/customers, the only v1 reference seen anywhere; treat as a docs typo, not a second version. (api-reference/introduction/introduction.md)

Idempotency. Idempotency-Key required on every POST; must NOT be sent on GET/PUT/PATCH/DELETE. 24h window: same key returns the original response. Retry must use the identical body — any changed/added/removed field (incl. nested, e.g. transfer initiation data) is a conflicting reuse, not a silent update. Reuse after 24h → 422. Bridge recommends a persisted UUID per logical request. (api-reference/introduction/idempotence.md)

Pagination. Cursor-based on item id, default newest→oldest. limit 1–100. starting_after=<last id> walks older; ending_before=<first id> walks newer; never both. {data: [...], count?}; stop when data is empty. Exception: GET /v0/webhook_events is ascending by event_sequence, limit up to 500 (§4). (api-reference/pagination.md)

Precision and rounding. Amounts truncate to whole USD cents even for 6-dp stablecoins — fractional cents "ignored, not processed or refunded." Rounding favors "at least the minimum amount of fees owed to all parties" — developer fee rounds up. Worked example: off-ramp $100,100.119999 USDT at 10 bps dev fee → truncate $100,100.11 → fee $100.10011 → round up $100.11 → customer receives $100,000.00. Clean fixed-output formula: Input = Output / 0.999, round up to the nearest cent (bakes in a ~10 bps "standard Bridge exchange fee"). Silent on non-USD fiat precision and crypto-to-crypto rounding. (platform/additional-information/precision.md)

Deprecation and versioning. "Deprecated" ≠ removed — migration guidance is inline on the deprecated surface, "sufficient advance notice before removing," no fixed sunset period stated; the changelog is the only announcement channel. Every webhook envelope carries api_version: "v0"; OpenAPI info.version is '1'; no header-based versioning documented. (api-reference/introduction/deprecation.md)

Sandbox behaviour. Base https://api.sandbox.bridge.xyz, per-developer keys. Webhook endpoints can be created in sandbox, but sandbox sends zero webhook events — real webhook testing needs production keys and a live endpoint (the load-bearing fact behind the signature-scheme caveat in §3). POST /v0/customers/{id}/simulate_kyc_approval (sandbox-only) sets KYC approved, fills required data from existing/sandbox defaults, approves pending endorsements. Bridge Wallets: creation returns a fake address bypassing the external provider; POST …/wallets/{id}/simulate_deposit {amount, currency} runs the full deposit pipeline to a terminal state. Silent on: transfer/VA simulation, data reset, rate limits. (api-reference/sandbox/simulate-kyc-approval-sandbox-only.md, platform/wallets/sandbox.md)

Implications for Stables

Idempotency-Key derivation must be stable per logical operation, never embed a mutable field — bridge-sdk's HasIdempotencyKey trait (bridge-development skill) is the in-repo mechanism. Pagination cursors map onto this repo's mirror backfill/poll conventions (app-modules/rails/README.md). Precision: Bridge amounts must be stored as decimal strings (never floats — the SDK already enforces this) and reconciliation must expect final_amount ≤ initial_amount − fees with cent truncation, never bit-for-bit against 6-dp on-chain amounts. Because sandbox sends zero webhook events, no Bridge webhook path here can be end-to-end tested against a real delivery pre-productionBridgeSignatureValidatorTest/BridgeTenantResolverTest are necessarily synthetic; production go-live carries first-real-event verification risk (§3).

7. Receipts and pricing

Receipts. "Bridge is required to send receipts for transactions processed through our system" — content: amount, fees, Bridge's legal disclosures; branding customised during integration. Transfer payloads carry a receipt object (gas_fee, exchange_fee, developer_fee, initial_amount, subtotal_amount, final_amount, optionally destination_tx_hash and urlhttps://dashboard.bridge.xyz/transaction/{id}/receipt/{id}). Silent on delivery channel, who sends it, opt-out, localisation. (platform/additional-information/receipts.md)

Pricing. The entire page: "Please reach out to sales@bridge.xyz to discuss pricing." No rates/tiers/fee schedule published. Adjacent facts: FedNow offramp beta is $0.50/transfer existing devs, $1.00 new (changelog 08/17/2026); developer fees are separately configurable via the Developers API tag (not fetched); precision's Input = Output / 0.999 implies a ~10 bps "standard Bridge exchange fee" but is not an explicit price statement. (platform/additional-information/pricing.md)

Implications for Stables

Surface Bridge's receipt.url in transaction detail rather than re-rendering its legal disclosure content (see BridgeTransferUpdatedHandler, §2). Pricing has no programmatic source — any fee assumption in rate quoting must come from the Developers fee-configuration API or a commercial agreement, never scraped from public docs.

8. Stablecoin issuance and rewards

No mint/burn API. "As issuer, Bridge handles all minting and burning for you" — no documented endpoint; both are automatic side effects of the orchestration/transfer pipeline. Mint: incoming fiat deposit → allocate to reserve accounts → mint on-chain → deliver to user's wallet. Burn: incoming on-chain stablecoin → burn → release fiat from reserves → send to bank or crypto address. Backing: "at least 1:1 by equivalent fiat value in reserves." Redemption timing isn't stated here (see reserve-management). (platform/issuance/minting-and-burning.md)

Liquidity allocation endpoint. POST /v0/issuance/reserves/liquidity_allocation (Idempotency-Key), body {allocation_percent, allocation_minimum}{previous_*, new_*}; GET same path returns {allocation_percent, allocation_minimum}. Goal: reserves ≥100% collateralised; developer controls on-demand-liquid vs treasuries split, and within liquid, USD vs on-chain-stablecoin — each side has a percentage + a minimum; "if both on-demand balances are below their respective minimums, reserve allocations will be rebalanced accordingly." Silent on which stablecoin the endpoint targets (no ticker param) — an account-level knob, not per-coin as documented. (platform/issuance/reserve-management.md)

Reward/redemption table: treasuries ≈ EFFR − 20 bps, US banking hours (tokenized treasuries partly redeemable outside hours, "within 1 business day"); off-chain USD ≈ EFFR − 200 bps, US banking hours; on-chain stablecoins 0%, 24/7. $100m AUM examples: redemption-first 50/50 → ~2.2% effective; reward-first 10/90 → ~3.3% effective.

Transparency endpoint (public, no key, different host): GET https://transparency.bridge.xyz/v0/stablecoins/{stablecoin}last_updated, total_onchain_amount, total_reserve_amount, reserves[]{type: cash|treasury, amount}, collateralization_ratio (6-dp strings). usdb is queryable today. (platform/issuance/reporting-and-transparency.md)

USDB. Bridge's off-the-shelf closed-loop coin — "only usable within Bridge wallets and payment rails," not transferable to third parties or traded publicly; still supported indefinitely. OUSD (run by the independent Open Standard consortium) is Bridge's suggested open-loop alternative. USDB appears in transfers as currency: "usdb", payment_rail: "bridge_wallet". (platform/issuance/usdb.md, issuance-options.md)

Rewards. Accrue "continuously" on treasury allocation; cash reserves "generally don't generate rewards." Revenue-share wording is inconsistent even within one page — "all revenue (minus issuance fees)" vs "the majority." Payout by the 5th business day of the following month, as minted tokens to a specified wallet or fiat to a bank — developer's choice. Rewards history API (GET /v0/rewards/{currency}/history, changelog 06/22/2026): daily records, t-2 business-day lag, ≤90 days/page, cursor-paginated. "Coming soon" per the pages: self-service on-demand claim, automated per-user reward splitting. (platform/issuance/rewards.md)

Implications for Stables

No issuance work exists in this repo today — BridgeRailsProvider (D118) implements 11 of 17 capability interfaces over Onboarding/FiatRails/Conversion/Custody, not issuance; see provider-landscape §"Bridge's registered capability groups." If a future increment adds issuance: model mint/burn as ordinary transfer.* webhook events, not a separate call; the reserve-allocation endpoint is a single account-level knob suited to a treasury-ops maker/checker surface, not per-tenant; any user-facing yield display must be built on the t-2-lagged history API, never a live number.

9. Changelog — most recent ~20 entries

DateEntry
08/17/2026FedNow offramps beta (24/7 instant USD out); waitlist; $0.50/transfer existing devs, $1.00 new
07/28/2026USDT on Tempo (usdt.tempo) and USDC on XDC (usdc.xdc) added to Orchestration APIs
06/22/2026Webhook reactivation no longer replays backlog (effective 06/29); replay via list-upcoming + send
06/02/2026Same reactivation notice (duplicate entry with links, as published)
06/22/2026Issuance Rewards History API GET /v0/rewards/{currency}/history — daily, t-2 lag, ≤90 days/page
06/23/2026Prefunded wallets emit bridge_wallet.activity; fiat legs may still emit virtual_account.activity/static_memo.activity
06/02/2026Bridge Wallet history gains starting_time/ending_time (ISO 8601), combinable with id cursors
05/28/2026Liquidation Address return_instructions{address, memo?} replaces deprecated return_address
05/04/2026FedNow onramps live, auto-enabled; inspect payment_received_rail (Transfer) / payment_rail (VA)
05/04/2026Bridge Wallet activity webhooks + GET /v0/customers/{id}/wallets/{id}/history
04/27/2026POST /v0/customers/{id}/external_accounts/{id}/deactivate (soft-disable); DELETE re-documented
04/27/2026USDC and usDCBL on Aptos across orchestration
04/22/2026Transfers gain payment_received_rail (may differ from requested payment_rail)
04/20/2026USDC on Sui
04/20/2026Stellar memoless_to_address (muxed) deposits; memo flow retained
04/03/2026USDC on HyperEVM
04/01/2026[Beta] fixed fees + per-rail fees + min/max bounds for Virtual Account onramps (gated)
03/27/2026Tempo Mainnet across all products
03/27/2026New payment states refund_in_flight, refund_failed in Transfers/VAs/Liquidation Addresses + webhooks
03/27/2026Effective 05/01/2026: client_reference_id added to v0/customers + customer webhooks; rejection_reasons strings may change — treat as free-form
03/24/2026Prefunded Accounts API deprecated (still supported indefinitely; improvements go to Bridge Wallets)
03/23/2026Scoped (immutable, resource-level) API keys
03/23/2026GBP FPS on/offramps GA; requires faster_payments endorsement

Older entries (03/09/2026 → 07/15/2025, per the changelog page): USDT on Solana; USDT↔MXN/BRL via SPEI/Pix on Ethereum/Plasma/Tron; Tron USDT custodial wallets; External Account webhooks (03/09/2026, with deactivation_reason/deactivation_details); USDC.Celo ramps; per-transfer return_instructions for crypto returns; Fixed Outputs; EURC on Ethereum; USDT on Plasma; GBP FPS beta; USDG on Solana; BRL Pix; reverse exchange rates; missing_return_policy state; proof of address via documents[].purpose = proof_of_address. Dates on the changelog page are not strictly monotonic — the 06/22 and 06/02 duplicate-dated reactivation entries above are exactly as published.

10. Bridge doc inconsistencies / gaps

  • Signature hash count: Go/Python/Node/Java samples effectively double-hash; Ruby single-hashes. Never resolved on the signature page (§3).
  • Stale-webhook response code: signature page says 400; this app deliberately returns 401 for consistency with every other source (§3) — a documented app-side deviation, not a docs bug.
  • event_type prefixing: category table shows bare mutations, examples mix bare/prefixed, the OpenAPI schema asserts prefixed-is-canonical (§2).
  • external_acccount vs external_account: table has a typo (triple c); OpenAPI enum is correct; no JSON example exists for this category at all.
  • event_object_status: null for VA/wallet-activity events (state lives in event_object.type instead), populated for customer/kyc_link/transfer — an undocumented shape inconsistency.
  • "HTTP Basic Auth" wording: auth page calls the Api-Key header "HTTP Basic Auth," but the example is a bare custom header, not RFC 7617 Basic auth.
  • /v1/customers in the idempotency example: the only v1 reference anywhere; every other page uses /v0 — likely stale, unconfirmed.
  • Revenue-share wording: issuance overview says "all revenue (minus issuance fees)" in one paragraph, "the majority" in another, same page.
  • kyc_link.customer_id population timing: undocumented whether/when it surfaces in event_object_changes — every sampled example still shows null.
  • Delivery timeout / retry backoff: "as quickly as possible" and "exponential, up to two days" are the only guidance; no numeric timeout or schedule published.
  • Key rotation mechanics: undocumented for webhook signing keys (this app's BridgeSignatureValidator supports comma-separated multi-key rotation defensively, not because Bridge describes a rotation flow).

11. Open questions for Bridge

Consolidated + tracked in flow-alignment.md §Open questions; this section keeps this page's own detail.

  • Which hashing convention is correct for signature verification — single (Ruby) or double (Go/Python/Node/Java)? Unresolvable from docs; needs a real production delivery (sandbox sends zero events).
  • What is the actual delivery timeout, and the exact retry backoff schedule (intervals, jitter, cap) within the two-day window?
  • When exactly does kyc_link.customer_id populate, and does it surface in event_object_changes?
  • Is /v1/customers (idempotency guide) a live second API version, or a stale /v0 typo?
  • Does /v0/issuance/reserves/liquidity_allocation target one stablecoin per account, or is there an undocumented per-coin parameter for multi-coin issuers?
  • What triggers webhook signing-key rotation on Bridge's side — is there a notification, or is our comma-separated multi-key support purely defensive?

12. Fetched 2026-09-03

All paths relative to https://apidocs.bridge.xyz/, fetched 2026-09-03, HTTP 200 on first try.

  • Webhooks: platform/additional-information/webhooks/{overview,signature,structure}.md · api-reference/webhooks/{create-a-webhook-endpoint,update-a-webhook,delete-a-webhook, get-all-webhook-endpoints,list-upcoming-events,list-webhook-events,send-event,view-logs}.md · get-started/introduction/quick-start/setting-up-webhooks.md
  • API mechanics: api-reference/introduction/{introduction,idempotence,deprecation, postman}.md · api-reference/pagination.md
  • Receipts/pricing/precision: platform/additional-information/{precision,pricing,receipts, faq}.md
  • Sandbox: api-reference/sandbox/simulate-kyc-approval-sandbox-only.md · platform/wallets/sandbox.md
  • Issuance: platform/issuance/{overview,issuance-options,usdb,designing-your-stablecoin, orchestration,minting-and-burning,reserve-management,reporting-and-transparency,rewards, growing-your-stablecoin,faq}.md
  • Changelog: changelog/changelog.md
  • JSON-sample support (§5, via BRIEF-2): api-reference/kyc-links/{generate-the-links-needs-to-complete-kyc-for-an-individual-or-business, check-the-status-of-a-kyc-link}.md · platform/customers/customers/kyclinks.md · api-reference/external-accounts/retrieve-an-external-account-object.md · api-reference/bridge-wallets/get-transaction-history-for-a-bridge-wallet.md

← Bridge cluster index · ← Engineering wiki