simulations
Sandbox simulations (SC-38, P-89): every asynchronous outcome on demand — incoming payments and debits, payment status, returns and recalls, inbound recalls, exchange settlement, FX rate moves, direct-debit outcomes, card events, KYC outcomes, integrator events, statements, scheduled runs and provider outages. Backed by the sandbox bank, and by the Banking Circle and Integrated Finance sandboxes where they offer a simulation.
Available simulations and sandbox rules
GET /v1/simulations
- listSimulations
- API key scope balances:read
- Tenant customer
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: balances:read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Responses
200 OK
application/jsonenvironmentstringrequiredconnectionobject | nullrequiredFields of connection
idUuidrequiredproviderstringrequiredenvironmentstringrequired
dataarray of objectrequiredFields of data
kindSimulationKindrequiredmethodstringrequiredpathstringrequiredsummarystringrequiredprovidersarray of SimulationProviderrequiredavailablebooleanrequiredAvailable for the caller's connection.
rulesarray of stringrequired
rulesarray of objectrequiredDeterministic sandbox rules that need no endpoint.
Fields of rules
topicstringrequiredrulestringrequired
401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X GET "https://bank.wirebloom.com/v1/simulations" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/simulations", {
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
},
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"GET",
"https://bank.wirebloom.com/v1/simulations",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Simulate a card transaction event
POST /v1/simulations/cards/{cardId}/transactions
- simulateCardTransaction
- API key scope payments:write
- Tenant customer
A neutral card event (cards/transaction) as the card processor would send it: authorisation (hold), settlement, reversal, refund or decline.
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
cardIdrequired | path | Uuid | Identifier (cardId). |
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
phasestringrequiredamountMoneyrequiredrefstringTransaction ref (generated for an authorisation; required to reverse or settle one).
relatedRefstringRefund: the settled transaction it refunds.
merchantNamestringmccstringmerchantCountryCountryCodechannelstringdeclineReasonstring
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json404 Resource does not exist in this tenant (cross-tenant ids also return 404), or feature disabled (`feature-disabled`).
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/cards/{cardId}/transactions" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"phase": "authorisation",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/cards/{cardId}/transactions", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"phase": "authorisation",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/cards/{cardId}/transactions",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"phase": "authorisation",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
},
timeout=30,
)
response.raise_for_status()Simulate a direct-debit collection outcome
POST /v1/simulations/direct-debits/collections/{collectionId}/status
- simulateCollectionStatus
- API key scope payments:write
- Tenant customer
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
collectionIdrequired | path | Uuid | Identifier (collectionId). |
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
statusstringrequiredreasonCodestring
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json404 Resource does not exist in this tenant (cross-tenant ids also return 404), or feature disabled (`feature-disabled`).
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/direct-debits/collections/{collectionId}/status" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"status": "collected"
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/direct-debits/collections/{collectionId}/status", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"status": "collected"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/direct-debits/collections/{collectionId}/status",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"status": "collected"
},
timeout=30,
)
response.raise_for_status()Simulate the settlement of an exchange
POST /v1/simulations/exchanges/{exchangeId}/status
- simulateExchangeStatus
- API key scope exchanges:write
- Tenant customer
Applies to an exchange still processing at the sandbox bank.
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: exchanges:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
exchangeIdrequired | path | Uuid | Identifier (exchangeId). |
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
statusstringrequired
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json404 Resource does not exist in this tenant (cross-tenant ids also return 404), or feature disabled (`feature-disabled`).
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/exchanges/{exchangeId}/status" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"status": "completed"
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/exchanges/{exchangeId}/status", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"status": "completed"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/exchanges/{exchangeId}/status",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"status": "completed"
},
timeout=30,
)
response.raise_for_status()Move a sandbox FX rate
POST /v1/simulations/fx-rates
- simulateFxRateMove
- API key scope exchanges:write
- Tenant customer
Stored on the operator's sandbox connection (rateShiftsBps): every quote of the pair moves (the inverse pair the other way). applied; details.rate is the new rate.
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: exchanges:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
sellCurrencyCoderequiredbuyCurrencyCoderequiredmoveBpsintegerrequiredBasis points, ±5000;
0resets the pair.
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/fx-rates" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"sell": "GBP",
"buy": "GBP",
"moveBps": -5000
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/fx-rates", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"sell": "GBP",
"buy": "GBP",
"moveBps": -5000
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/fx-rates",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"sell": "GBP",
"buy": "GBP",
"moveBps": -5000
},
timeout=30,
)
response.raise_for_status()Simulate a direct debit taken from a balance
POST /v1/simulations/incoming-debits
- simulateIncomingDebit
- API key scope payments:write
- Tenant customer
Banking Circle sandbox only (POST /api/v1/payments/simulations/debits); 409 on other connections.
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/incoming-debits" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/incoming-debits", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/incoming-debits",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
},
timeout=30,
)
response.raise_for_status()Simulate an incoming payment
POST /v1/simulations/incoming-payments
- simulateIncomingPayment
- API key scope payments:write
- Tenant customer
Sandbox bank: an account.credited event through the webhook pipeline (queued). Banking Circle sandbox: POST /api/v1/payments/simulations/credits on the balance account (submitted; the IncomingPaymentProcessed notification follows). Integrated Finance sandbox: a provisioned account credit on the balance IBAN (inferred until IF-33).
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/incoming-payments" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/incoming-payments", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/incoming-payments",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
},
timeout=30,
)
response.raise_for_status()Simulate an inbound recall request
POST /v1/simulations/incoming-payments/{incomingPaymentId}/recall
- simulateIncomingRecall
- API key scope payments:write
- Tenant customer
Opens a partner compliance case (inbound_recall, provider sandbox) in the operator's queue (applied).
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
incomingPaymentIdrequired | path | Uuid | Identifier (incomingPaymentId). |
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
reasonCodestringrequired
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json404 Resource does not exist in this tenant (cross-tenant ids also return 404), or feature disabled (`feature-disabled`).
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/incoming-payments/{incomingPaymentId}/recall" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"reasonCode": "AC03"
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/incoming-payments/{incomingPaymentId}/recall", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"reasonCode": "AC03"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/incoming-payments/{incomingPaymentId}/recall",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"reasonCode": "AC03"
},
timeout=30,
)
response.raise_for_status()Simulate a KYC review outcome
POST /v1/simulations/kyc
- simulateKycOutcome
- API key scope payments:write
- Tenant customer
Applied as the KYC provider's applicantReviewed webhook: approved (GREEN), rejected (RED FINAL), retry (RED RETRY).
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
personIdUuidrequiredoutcomestringrequiredcommentstring
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/kyc" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"personId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"outcome": "approved"
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/kyc", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"personId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"outcome": "approved"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/kyc",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"personId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"outcome": "approved"
},
timeout=30,
)
response.raise_for_status()Simulate the outcome of a payment recall
POST /v1/simulations/payments/{paymentId}/recall
- simulatePaymentRecall
- API key scope payments:write
- Tenant customer
accepted: the funds come back (a return with the recall reason); rejected: recorded on the provider event log, nothing moves.
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
paymentIdrequired | path | Uuid | Identifier (paymentId). |
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
outcomestringrequiredreasonCodestring
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json404 Resource does not exist in this tenant (cross-tenant ids also return 404), or feature disabled (`feature-disabled`).
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/payments/{paymentId}/recall" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"outcome": "accepted"
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/payments/{paymentId}/recall", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"outcome": "accepted"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/payments/{paymentId}/recall",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"outcome": "accepted"
},
timeout=30,
)
response.raise_for_status()Simulate the return of a payment
POST /v1/simulations/payments/{paymentId}/return
- simulatePaymentReturn
- API key scope payments:write
- Tenant customer
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
paymentIdrequired | path | Uuid | Identifier (paymentId). |
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
Partial return with amount; the payment amount otherwise.
reasonCodestringamountMoney
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json404 Resource does not exist in this tenant (cross-tenant ids also return 404), or feature disabled (`feature-disabled`).
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/payments/{paymentId}/return" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/payments/{paymentId}/return", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/payments/{paymentId}/return",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={},
timeout=30,
)
response.raise_for_status()Simulate the provider status of a payment
POST /v1/simulations/payments/{paymentId}/status
- simulatePaymentStatus
- API key scope payments:write
- Tenant customer
A payment sent through the sandbox bank (409 before it is sent or on a partner connection). The worker applies the stated status without asking the sandbox bank.
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
paymentIdrequired | path | Uuid | Identifier (paymentId). |
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
statusstringrequiredfailureReasonstring
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json404 Resource does not exist in this tenant (cross-tenant ids also return 404), or feature disabled (`feature-disabled`).
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/payments/{paymentId}/status" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"status": "processing"
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/payments/{paymentId}/status", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"status": "processing"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/payments/{paymentId}/status",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"status": "processing"
},
timeout=30,
)
response.raise_for_status()Simulate a sandbox bank outage
POST /v1/simulations/provider-outage
- simulateProviderOutage
- API key scope payments:write
- Tenant customer
Bank calls fail with a retryable provider error until the time given (applied): rehearse retries and backoff.
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
durationSecondsintegerrequiredSeconds from now;
0ends the outage.
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/provider-outage" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"durationSeconds": 0
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/provider-outage", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"durationSeconds": 0
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/provider-outage",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"durationSeconds": 0
},
timeout=30,
)
response.raise_for_status()Run a scheduled payment now
POST /v1/simulations/scheduled-payments/{scheduledPaymentId}/run-now
- simulateScheduledRun
- API key scope payments:write
- Tenant customer
An active schedule with a next occurrence is made due now and handed to the worker (409 otherwise).
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
scheduledPaymentIdrequired | path | Uuid | Identifier (scheduledPaymentId). |
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json404 Resource does not exist in this tenant (cross-tenant ids also return 404), or feature disabled (`feature-disabled`).
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/scheduled-payments/{scheduledPaymentId}/run-now" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/simulations/scheduled-payments/{scheduledPaymentId}/run-now", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
},
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/scheduled-payments/{scheduledPaymentId}/run-now",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Simulate a statement becoming available
POST /v1/simulations/statements
- simulateStatement
- API key scope webhooks:manage
- Tenant customer
A statement.available integrator event for the balance.
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: webhooks:manage.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/statements" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908"
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/statements", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/statements",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908"
},
timeout=30,
)
response.raise_for_status()Send an integrator event to your endpoints
POST /v1/simulations/webhook-events
- simulateWebhookEvent
- API key scope webhooks:manage
- Tenant customer
Delivered to the customer's active endpoints subscribed to the type, with data.sandbox: true.
Sandbox only: 404 feature-disabled wherever the sandbox is off (always in production). Callers: a wb_test_ API key of the customer, or a member session of a developer sandbox workspace (403 for live keys and other sessions). Every simulation answers 202 SimulationResult; queued outcomes arrive through the normal pipeline (ledger, notifications, integrator webhooks) within seconds. Rules: docs/SANDBOX.md.
API key scope: webhooks:manage.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
X-Tenant-Idrequired | header | Uuid | Tenant context: the operator tenant id (staff operations) or customer tenant id (customer operations). Validated against the caller's memberships; mismatch → |
X-Request-Id | header | string | Client-supplied correlation id. Generated by the server when absent; always echoed in the response and in problem details. |
Idempotency-Key | header | string | Optional idempotency key; same semantics as on money operations. |
Request body
typeIntegratorEventTyperequiredobjectIdUuidstatusstringamountMoney
Responses
202 Accepted
application/jsonsimulationIdUuidrequiredkindSimulationKindrequiredstatusstringrequiredqueued: a provider event was stored and handed to the workers;submitted: the partner sandbox accepted it and notifies by webhook;applied: done synchronously.providerSimulationProviderrequiredproviderEventIdsarray of Uuidrequiredproviders.eventsrows written (provider event log).providerReferencestring | nullrequireddetailsobjectrequiredPer kind (amounts, refs, rates, case id, …).
Fields of details
400 Malformed request: unparseable JSON, or an invalid header, path or query parameter (`errors[].field` is `header.X`, `path.x` or `query.x`). Body validation failures are 422 `validation-error`.
application/problem+json401 Missing, expired or invalid credentials (`unauthenticated`, `session-expired` with `reason` `idle` / `revoked` / `expired`, `invalid-api-key`, `mfa-required`).
application/problem+json403 Authenticated but not allowed: missing capability or scope, tenant not in memberships, `step-up-required`, IP not allow-listed, impersonation restriction.
application/problem+json409 State conflict: `invalid-transition`, `duplicate-recipient`, `quote-expired`, `insufficient-funds`, `idempotency-key-in-use` (with Retry-After), `not-cancellable`.
application/problem+json422 Semantically invalid request; `errors[]` lists field-level problems. Also `idempotency-key-reused` when the key was used with a different payload, `limit-exceeded`, `recipient-not-approved`.
application/problem+json429 Rate limit exceeded.
application/problem+jsondefault Unexpected error (`500 internal-error`, `501 not-implemented`, `502 provider-error`, `503 service-unavailable`, `504 provider-timeout`). Money operations that time out at the provider are never retried blindly; their state becomes `exception`/unknown and is reconciled.
application/problem+json
Code samples
curl -X POST "https://bank.wirebloom.com/v1/simulations/webhook-events" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"type": "webhook.test"
}'const response = await fetch("https://bank.wirebloom.com/v1/simulations/webhook-events", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Content-Type": "application/json",
},
body: JSON.stringify({
"type": "webhook.test"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/simulations/webhook-events",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"type": "webhook.test"
},
timeout=30,
)
response.raise_for_status()