payments
Payments, internal transfers, add money, exchanges and quotes, forward contracts and held rates, scheduled payments, direct debits (mandates, collections), bulk payments, approvals and funds requests.
Add money (deposit details or conversion order)
POST /v1/add-money
- addMoney
- API key scope payments:write
- Idempotency-Key required
- Tenant customer
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
bank_transfer: returns deposit details (Same currency). conversion: creates a conversion order from fromBalanceId at the locked quoteId rate (Convert currency).
methodstringrequiredbalanceIdUuidrequiredamountPositiveMoney | nullfromBalanceIdUuid | nullquoteIdUuid | nullfixedSideFixedSide | null
Responses
200 OK
application/jsonmethodstringrequireddepositDetailsarray of AccountDetailsexchangeExchange | null
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/add-money" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"method": "conversion",
"balanceId": "0192a6f1-1111-7000-8000-00000000b003",
"fromBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"amount": {
"amountMinor": "250000",
"currency": "EUR"
},
"fixedSide": "buy",
"quoteId": "0192a6f1-4444-7000-8000-00000000d001"
}'const response = await fetch("https://bank.wirebloom.com/v1/add-money", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"method": "conversion",
"balanceId": "0192a6f1-1111-7000-8000-00000000b003",
"fromBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"amount": {
"amountMinor": "250000",
"currency": "EUR"
},
"fixedSide": "buy",
"quoteId": "0192a6f1-4444-7000-8000-00000000d001"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/add-money",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"method": "conversion",
"balanceId": "0192a6f1-1111-7000-8000-00000000b003",
"fromBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"amount": {
"amountMinor": "250000",
"currency": "EUR"
},
"fixedSide": "buy",
"quoteId": "0192a6f1-4444-7000-8000-00000000d001"
},
timeout=30,
)
response.raise_for_status()Approvals inbox
GET /v1/approvals
- listApprovals
- API key scope payments:read
- Tenant any
Customer members see their customer's approvals. Operator staff (x-tenant: any): with X-Tenant-Id set to a customer they read that customer; with their operator id they read every customer of the operator (RLS operator scope) (approvals oversight); staff never decide customer approvals, so mine returns nothing for them and canDecide is false. filter[subjectId] lists the approvals of one payment, recipient or bulk upload.
API key scope: payments:read.
Conditional GET (P12-T07): the response carries a weak ETag of its content; send it back as If-None-Match when polling and the API answers 304 without a body while nothing changed.
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. |
cursor | query | string | Opaque cursor from |
limit | query | integer | Page size (max 100). |
sort | query | string | Sort order; prefix |
filter | query | object | Filters as |
withTotal | query | boolean | Include |
If-None-Match | header | string | Conditional GET; |
Responses
304 Not modified (`If-None-Match` matched).
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+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/approvals" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/approvals", {
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/approvals",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Get approval
GET /v1/approvals/{approvalId}
- getApproval
- API key scope payments:read
- Tenant any
Read access as GET /approvals (operator staff: any customer of the operator).
API key scope: payments:read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
approvalIdrequired | path | Uuid | Identifier (approvalId). |
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/jsonidUuidrequiredread-onlyFields of id
subjectTypeApprovalSubjectTyperequiredsubjectIdUuidrequiredsubjectSummaryobjectrequiredFields of subjectSummary
titlestringrequiredamountMoney | nullrecipientNamestring | nullRecipient (payments, recipients) or counterparty name.
sourceBalanceIdUuid | nullsourceBalanceNamestring | nullrailRail | nullitemCountinteger | nullBulk uploads: payments in the batch.
recipientMaskedIdentifierstring | nullMasked account identifier of the recipient the approver binds to (payments: the snapshot taken at submission, which the payment is sent to or refused against; recipients: the current details). Null for other subjects (security audit S-01, D-47).
tierintegerrequiredstatusApprovalStatusrequiredread-onlyFields of status
requiredApprovalsintegerrequiredreceivedintegerrequiredread-onlyApprovals received so far (
approveddecisions).decisionsarray of objectrequiredrequestedByUuidrequiredrequestedByNamestringcanDecidebooleanrequiredread-onlyWhether the caller is an eligible approver (not the requester unless self-approval allowed).
expiresAtTimestamp | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
policyobjectread-onlyThe effective policy tier the request is judged against.
Fields of policy
kindApprovalPolicyKind | nullsourcestringrequiredsnapshot: the tier captured when the request opened;policy: the current policy;default: the built-in single approval;recipient: recipient approval mode.tierApprovalTierrequiredissuesarray of objectrequiredFields of issues
codestringrequiredmessagestringrequired
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+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/approvals/{approvalId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/approvals/{approvalId}", {
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/approvals/{approvalId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()List bulk uploads
GET /v1/bulk-payments
- listBulkPayments
- API key scope payments:read
- Tenant customer
API key scope: payments: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. |
cursor | query | string | Opaque cursor from |
limit | query | integer | Page size (max 100). |
sort | query | string | Sort order; prefix |
filter | query | object | Filters as |
Responses
200 OK
application/jsonCursor-paginated list of BulkPayment.
dataarray of BulkPaymentrequiredpagePageInforequired
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+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/bulk-payments" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/bulk-payments", {
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/bulk-payments",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Upload bulk payments file for validation
POST /v1/bulk-payments
- createBulkPayment
- API key scope payments:write
- Idempotency-Key required
- Tenant customer
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
Upload the CSV first via POST /documents (kind=bulk_payments). Validation is asynchronous.
Responses
202 Accepted
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
documentIdUuidrequiredsourceBalanceIdUuidrequiredstatusBulkUploadStatusrequiredread-onlyFields of status
rowsTotalintegerrequiredrowsOkintegerrequiredrowsFailedintegerrequiredtotalMoney | nullresultsDocumentIdstring | null (uuid)read-onlyPer-row results file (CSV document,
GET /documents/{documentId}/download) written after validation and after submission; null until produced.createdByUuidread-onlyFields of createdBy
createdAtTimestamprequiredread-onlyFields of createdAt
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/bulk-payments" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"documentId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"sourceBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908"
}'const response = await fetch("https://bank.wirebloom.com/v1/bulk-payments", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"documentId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"sourceBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/bulk-payments",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"documentId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"sourceBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908"
},
timeout=30,
)
response.raise_for_status()Bulk upload status
GET /v1/bulk-payments/{bulkPaymentId}
- getBulkPayment
- API key scope payments:read
- Tenant customer
API key scope: payments:read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
bulkPaymentIdrequired | path | Uuid | Identifier (bulkPaymentId). |
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/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
documentIdUuidrequiredsourceBalanceIdUuidrequiredstatusBulkUploadStatusrequiredread-onlyFields of status
rowsTotalintegerrequiredrowsOkintegerrequiredrowsFailedintegerrequiredtotalMoney | nullresultsDocumentIdstring | null (uuid)read-onlyPer-row results file (CSV document,
GET /documents/{documentId}/download) written after validation and after submission; null until produced.createdByUuidread-onlyFields of createdBy
createdAtTimestamprequiredread-onlyFields of createdAt
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+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/bulk-payments/{bulkPaymentId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/bulk-payments/{bulkPaymentId}", {
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/bulk-payments/{bulkPaymentId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Cancel bulk upload
POST /v1/bulk-payments/{bulkPaymentId}/cancel
- cancelBulkPayment
- API key scope payments:write
- Tenant customer
API key scope: payments:write.
Stalled submissions (re-review R-05): a batch in submitting whose background run has stopped (no progress for two minutes) can be cancelled: rows not yet submitted become failed with code cancelled, payments already created stay and the batch ends submitted / partially_submitted (or cancelled when none was created, which also closes its batch approval). A batch that is still progressing answers 409 not-cancellable. Batches that stay stalled are closed by the platform after 30 minutes (row code submission_stalled), and rows not yet submitted when the batch approval expires fail with code approval_expired.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
bulkPaymentIdrequired | path | Uuid | Identifier (bulkPaymentId). |
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/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
documentIdUuidrequiredsourceBalanceIdUuidrequiredstatusBulkUploadStatusrequiredread-onlyFields of status
rowsTotalintegerrequiredrowsOkintegerrequiredrowsFailedintegerrequiredtotalMoney | nullresultsDocumentIdstring | null (uuid)read-onlyPer-row results file (CSV document,
GET /documents/{documentId}/download) written after validation and after submission; null until produced.createdByUuidread-onlyFields of createdBy
createdAtTimestamprequiredread-onlyFields of createdAt
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/bulk-payments/{bulkPaymentId}/cancel" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/bulk-payments/{bulkPaymentId}/cancel", {
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/bulk-payments/{bulkPaymentId}/cancel",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Per-row validation results
GET /v1/bulk-payments/{bulkPaymentId}/rows
- listBulkPaymentRows
- API key scope payments:read
- Tenant customer
API key scope: payments:read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
bulkPaymentIdrequired | path | Uuid | Identifier (bulkPaymentId). |
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. |
cursor | query | string | Opaque cursor from |
limit | query | integer | Page size (max 100). |
sort | query | string | Sort order; prefix |
filter | query | object | Filters as |
Responses
200 OK
application/jsonCursor-paginated list of BulkPaymentRow.
dataarray of BulkPaymentRowrequiredpagePageInforequired
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+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/bulk-payments/{bulkPaymentId}/rows" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/bulk-payments/{bulkPaymentId}/rows", {
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/bulk-payments/{bulkPaymentId}/rows",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Submit validated rows as payments
POST /v1/bulk-payments/{bulkPaymentId}/submit
- submitBulkPayment
- API key scope payments:write
- Idempotency-Key required
- Tenant customer
Asynchronous (scalability audit X-12): moves the batch to submitting, opens the batch approval when the total falls in an approval tier, and returns 202 with the job (Location: /v1/jobs/{jobId}). Every valid row then becomes a payment through the single-payment path, each with its row status in one transaction, so an interrupted run resumes without duplicates. Submitting a batch that is already submitting returns the same job (and resumes it when it stalled, for the original submitter). 429 rate-limited when too many batches of the operator are being submitted. Decisions on the batch approval are refused (409) until the batch leaves submitting.
Step-up: requires a verified step-up challenge for action payment.above_threshold within the last 5 minutes (session/bearer only). Otherwise 403 with problem type step-up-required; the step-up check runs before body validation.
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
API key scope: payments:write.
Expired batch approval (re-review R-05): re-submitting a batch in submitting whose batch approval is no longer pending answers 409 invalid-transition; the remaining rows are closed as failed (approval_expired).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
bulkPaymentIdrequired | path | Uuid | Identifier (bulkPaymentId). |
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Responses
202 Accepted
application/json202of submit: the job that creates the payments in the background (kindbulk_validation, pollGET /jobs/{jobId}forprogress) and the batch as it stands (statussubmitting; pollGET /bulk-payments/{bulkPaymentId}for the finalsubmitted/partially_submittedand the row results).idUuidrequiredread-onlyFields of id
kindstringrequiredstatusstringrequiredprogressintegerresultUrlstring | null (uri)Pre-signed download URL (valid 15 minutes) when
status=succeeded.errorProblem | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
finishedAtTimestamp | nullbulkPaymentBulkPaymentrequired
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/bulk-payments/{bulkPaymentId}/submit" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)"const response = await fetch("https://bank.wirebloom.com/v1/bulk-payments/{bulkPaymentId}/submit", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
},
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/bulk-payments/{bulkPaymentId}/submit",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
},
timeout=30,
)
response.raise_for_status()List direct debit collections
GET /v1/collections
- listCollections
- API key scope payments:read
- Tenant customer
Feature flag: payments.direct_debits; returns 404 with problem type feature-disabled when the flag is off for the operator.
API key scope: payments: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. |
cursor | query | string | Opaque cursor from |
limit | query | integer | Page size (max 100). |
sort | query | string | Sort order; prefix |
filter | query | object | Filters as |
Responses
200 OK
application/jsonCursor-paginated list of Collection.
dataarray of CollectionrequiredpagePageInforequired
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+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/collections" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/collections", {
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/collections",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Request a collection on a mandate
POST /v1/collections
- createCollection
- API key scope payments:write
- Idempotency-Key required
- Tenant customer
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
Feature flag: payments.direct_debits; returns 404 with problem type feature-disabled when the flag is off for the operator.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
mandateIdUuidrequiredamountPositiveMoneyrequireddueDateDaterequiredreferencestring | null
Responses
201 Created
application/jsonidUuidrequiredread-onlyFields of id
mandateIdUuidrequiredamountMoneyrequireddueDateDaterequiredstatusCollectionStatusrequiredread-onlyFields of status
providerRefstring | nullread-onlytransactionIdUuid | nullfailureReasonstring | nullread-onlycreatedAtTimestamprequiredread-onlyFields of createdAt
referencestring | nullsequenceTypestringread-onlysubmitOnDate | nullcollectedAtTimestamp | nullreturnReasonCodestring | nullread-onlyR-transaction reason code (SEPA / Bacs ARUDD).
returnedAtTimestamp | nullscheduledPaymentIdUuid | null
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/collections" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"mandateId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"dueDate": "2026-09-30"
}'const response = await fetch("https://bank.wirebloom.com/v1/collections", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"mandateId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"dueDate": "2026-09-30"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/collections",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"mandateId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"dueDate": "2026-09-30"
},
timeout=30,
)
response.raise_for_status()Get collection
GET /v1/collections/{collectionId}
- getCollection
- API key scope payments:read
- Tenant customer
Feature flag: payments.direct_debits; returns 404 with problem type feature-disabled when the flag is off for the operator.
API key scope: payments:read.
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. |
Responses
200 OK
application/jsonidUuidrequiredread-onlyFields of id
mandateIdUuidrequiredamountMoneyrequireddueDateDaterequiredstatusCollectionStatusrequiredread-onlyFields of status
providerRefstring | nullread-onlytransactionIdUuid | nullfailureReasonstring | nullread-onlycreatedAtTimestamprequiredread-onlyFields of createdAt
referencestring | nullsequenceTypestringread-onlysubmitOnDate | nullcollectedAtTimestamp | nullreturnReasonCodestring | nullread-onlyR-transaction reason code (SEPA / Bacs ARUDD).
returnedAtTimestamp | nullscheduledPaymentIdUuid | null
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+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/collections/{collectionId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/collections/{collectionId}", {
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/collections/{collectionId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Cancel collection (before submission)
POST /v1/collections/{collectionId}/cancel
- cancelCollection
- API key scope payments:write
- Tenant customer
Feature flag: payments.direct_debits; returns 404 with problem type feature-disabled when the flag is off for the operator.
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. |
Responses
200 OK
application/jsonidUuidrequiredread-onlyFields of id
mandateIdUuidrequiredamountMoneyrequireddueDateDaterequiredstatusCollectionStatusrequiredread-onlyFields of status
providerRefstring | nullread-onlytransactionIdUuid | nullfailureReasonstring | nullread-onlycreatedAtTimestamprequiredread-onlyFields of createdAt
referencestring | nullsequenceTypestringread-onlysubmitOnDate | nullcollectedAtTimestamp | nullreturnReasonCodestring | nullread-onlyR-transaction reason code (SEPA / Bacs ARUDD).
returnedAtTimestamp | nullscheduledPaymentIdUuid | null
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/collections/{collectionId}/cancel" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/collections/{collectionId}/cancel", {
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/collections/{collectionId}/cancel",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()List exchanges
GET /v1/exchanges
- listExchanges
- API key scope exchanges:read
- Tenant customer
API key scope: exchanges: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. |
cursor | query | string | Opaque cursor from |
limit | query | integer | Page size (max 100). |
sort | query | string | Sort order; prefix |
filter | query | object | Filters as |
q | query | string | Free-text search (trigram; min 2 characters). |
Responses
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+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/exchanges" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/exchanges", {
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/exchanges",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Execute exchange from a quote
POST /v1/exchanges
- createExchange
- API key scope exchanges:write
- Idempotency-Key required
- Tenant customer
Exchanges are subject to payment approval policies when enabled.
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
Execute a live quote. Expired quote → 409 quote-expired.
Responses
201 Created
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
kindExchangeKindrequiredstatusExchangeStatusrequiredread-onlyFields of status
sellBalanceIdUuidrequiredbuyBalanceIdUuidrequiredsellAmountMoneyrequiredbuyAmountMoneyrequiredrateRaterequiredfixedSideFixedSiderequiredquoteIdUuidrequiredfeeMoney | nullsettlementDateDate | nulldepositMoney | nullremainingMoney | nullorderIdstringrequiredread-onlyHuman order id shown on confirmations.
providerRefstring | nullread-onlycreatedByUuid | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
completedAtTimestamp | nullpurposestringread-onlyWhat the conversion is for: a direct exchange, an add-money conversion order or the funding of a cross-currency payment.
statusReasonstring | nullread-onlyWhy the exchange failed or was cancelled.
marginCallobject | nullread-onlyOpen margin call on a forward: deposit top-up required (
POST /forward-contracts/{exchangeId}/deposit).drawdownCountintegerread-onlyDrawdowns requested on a forward or held-rate contract.
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/exchanges" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"quoteId": "0192a6f1-4444-7000-8000-00000000d001",
"sellBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"buyBalanceId": "0192a6f1-1111-7000-8000-00000000b003"
}'const response = await fetch("https://bank.wirebloom.com/v1/exchanges", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"quoteId": "0192a6f1-4444-7000-8000-00000000d001",
"sellBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"buyBalanceId": "0192a6f1-1111-7000-8000-00000000b003"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/exchanges",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"quoteId": "0192a6f1-4444-7000-8000-00000000d001",
"sellBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"buyBalanceId": "0192a6f1-1111-7000-8000-00000000b003"
},
timeout=30,
)
response.raise_for_status()Get exchange
GET /v1/exchanges/{exchangeId}
- getExchange
- API key scope exchanges:read
- Tenant customer
API key scope: exchanges:read.
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. |
Responses
200 OK
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
kindExchangeKindrequiredstatusExchangeStatusrequiredread-onlyFields of status
sellBalanceIdUuidrequiredbuyBalanceIdUuidrequiredsellAmountMoneyrequiredbuyAmountMoneyrequiredrateRaterequiredfixedSideFixedSiderequiredquoteIdUuidrequiredfeeMoney | nullsettlementDateDate | nulldepositMoney | nullremainingMoney | nullorderIdstringrequiredread-onlyHuman order id shown on confirmations.
providerRefstring | nullread-onlycreatedByUuid | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
completedAtTimestamp | nullpurposestringread-onlyWhat the conversion is for: a direct exchange, an add-money conversion order or the funding of a cross-currency payment.
statusReasonstring | nullread-onlyWhy the exchange failed or was cancelled.
marginCallobject | nullread-onlyOpen margin call on a forward: deposit top-up required (
POST /forward-contracts/{exchangeId}/deposit).drawdownCountintegerread-onlyDrawdowns requested on a forward or held-rate contract.
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+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/exchanges/{exchangeId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/exchanges/{exchangeId}", {
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/exchanges/{exchangeId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Exchange order confirmation (PDF)
GET /v1/exchanges/{exchangeId}/confirmation
- getExchangeConfirmation
- API key scope statements:read
- Tenant customer
The branded confirmation PDF, rendered on first request and cached (same behaviour as GET /payments/{paymentId}/confirmation).
API key scope: statements:read.
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. |
Responses
200 OK
application/pdf401 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+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/exchanges/{exchangeId}/confirmation" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/exchanges/{exchangeId}/confirmation", {
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/exchanges/{exchangeId}/confirmation",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Create FX quote
POST /v1/exchanges/quotes
- createQuote
- API key scope exchanges:write
- Tenant customer
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
amount.currency must equal the fixed side currency. settlementDate required for forward.
sellCurrencyCurrencyCoderequiredbuyCurrencyCurrencyCoderequiredamountPositiveMoneyrequiredfixedSideFixedSiderequiredkindExchangeKindsettlementDateDate | nullsellBalanceIdUuid | nullbuyBalanceIdUuid | nullholdMinutesinteger | nullHeld rates: how long the rate is held (default: operator setting
exchange.heldRateDefaultMinutes).
Responses
201 Created
application/jsonFirm quote; typically valid 30 seconds (countdown in the UI). Refresh to get a new rate.
idUuidrequiredread-onlyFields of id
sellAmountMoneyrequiredbuyAmountMoneyrequiredrateRaterequiredinverseRateRaterequiredfixedSideFixedSiderequiredkindExchangeKindrequiredfeeMoney | nullsettlementDateDate | nulldepositRequiredMoney | nullexpiresAtTimestamprequiredusedbooleanrequiredcreatedAtTimestamprequiredread-onlyFields of createdAt
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/exchanges/quotes" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"sellCurrency": "GBP",
"buyCurrency": "EUR",
"amount": {
"amountMinor": "100000",
"currency": "EUR"
},
"fixedSide": "buy",
"kind": "spot"
}'const response = await fetch("https://bank.wirebloom.com/v1/exchanges/quotes", {
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({
"sellCurrency": "GBP",
"buyCurrency": "EUR",
"amount": {
"amountMinor": "100000",
"currency": "EUR"
},
"fixedSide": "buy",
"kind": "spot"
}),
});
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/exchanges/quotes",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"sellCurrency": "GBP",
"buyCurrency": "EUR",
"amount": {
"amountMinor": "100000",
"currency": "EUR"
},
"fixedSide": "buy",
"kind": "spot"
},
timeout=30,
)
response.raise_for_status()Get quote
GET /v1/exchanges/quotes/{quoteId}
- getQuote
- API key scope exchanges:read
- Tenant customer
API key scope: exchanges:read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
quoteIdrequired | path | Uuid | Identifier (quoteId). |
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/jsonFirm quote; typically valid 30 seconds (countdown in the UI). Refresh to get a new rate.
idUuidrequiredread-onlyFields of id
sellAmountMoneyrequiredbuyAmountMoneyrequiredrateRaterequiredinverseRateRaterequiredfixedSideFixedSiderequiredkindExchangeKindrequiredfeeMoney | nullsettlementDateDate | nulldepositRequiredMoney | nullexpiresAtTimestamprequiredusedbooleanrequiredcreatedAtTimestamprequiredread-onlyFields of createdAt
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+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/exchanges/quotes/{quoteId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/exchanges/quotes/{quoteId}", {
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/exchanges/quotes/{quoteId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Refresh an expired quote (new quote, same terms)
POST /v1/exchanges/quotes/{quoteId}/refresh
- refreshQuote
- API key scope exchanges:write
- Tenant customer
API key scope: exchanges:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
quoteIdrequired | path | Uuid | Identifier (quoteId). |
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
201 Created
application/jsonFirm quote; typically valid 30 seconds (countdown in the UI). Refresh to get a new rate.
idUuidrequiredread-onlyFields of id
sellAmountMoneyrequiredbuyAmountMoneyrequiredrateRaterequiredinverseRateRaterequiredfixedSideFixedSiderequiredkindExchangeKindrequiredfeeMoney | nullsettlementDateDate | nulldepositRequiredMoney | nullexpiresAtTimestamprequiredusedbooleanrequiredcreatedAtTimestamprequiredread-onlyFields of createdAt
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/exchanges/quotes/{quoteId}/refresh" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/exchanges/quotes/{quoteId}/refresh", {
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/exchanges/quotes/{quoteId}/refresh",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()List forward contracts and held rates
GET /v1/forward-contracts
- listForwardContracts
- API key scope exchanges:read
- Tenant customer
Forwards and held rates (filter[kind]=held_rate): there is no separate /held-rates resource; held rates are booked, listed and drawn down here.
Feature flag: fx.forwards; returns 404 with problem type feature-disabled when the flag is off for the operator.
API key scope: exchanges: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. |
cursor | query | string | Opaque cursor from |
limit | query | integer | Page size (max 100). |
sort | query | string | Sort order; prefix |
filter | query | object | Filters as |
q | query | string | Free-text search (trigram; min 2 characters). |
Responses
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+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/forward-contracts" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/forward-contracts", {
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/forward-contracts",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Book forward contract / held rate
POST /v1/forward-contracts
- createForwardContract
- API key scope exchanges:write
- Idempotency-Key required
- Tenant customer
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
Feature flag: fx.forwards; returns 404 with problem type feature-disabled when the flag is off for the operator.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
Book a forward or held-rate contract from a forward/held_rate quote. Deposit is taken from depositBalanceId when required.
Responses
201 Created
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
kindExchangeKindrequiredstatusExchangeStatusrequiredread-onlyFields of status
sellBalanceIdUuidrequiredbuyBalanceIdUuidrequiredsellAmountMoneyrequiredbuyAmountMoneyrequiredrateRaterequiredfixedSideFixedSiderequiredquoteIdUuidrequiredfeeMoney | nullsettlementDateDate | nulldepositMoney | nullremainingMoney | nullorderIdstringrequiredread-onlyHuman order id shown on confirmations.
providerRefstring | nullread-onlycreatedByUuid | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
completedAtTimestamp | nullpurposestringread-onlyWhat the conversion is for: a direct exchange, an add-money conversion order or the funding of a cross-currency payment.
statusReasonstring | nullread-onlyWhy the exchange failed or was cancelled.
marginCallobject | nullread-onlyOpen margin call on a forward: deposit top-up required (
POST /forward-contracts/{exchangeId}/deposit).drawdownCountintegerread-onlyDrawdowns requested on a forward or held-rate contract.
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/forward-contracts" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"quoteId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"sellBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"buyBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908"
}'const response = await fetch("https://bank.wirebloom.com/v1/forward-contracts", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"quoteId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"sellBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"buyBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/forward-contracts",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"quoteId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"sellBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"buyBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908"
},
timeout=30,
)
response.raise_for_status()Get forward contract
GET /v1/forward-contracts/{exchangeId}
- getForwardContract
- API key scope exchanges:read
- Tenant customer
Feature flag: fx.forwards; returns 404 with problem type feature-disabled when the flag is off for the operator.
API key scope: exchanges:read.
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. |
Responses
200 OK
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
kindExchangeKindrequiredstatusExchangeStatusrequiredread-onlyFields of status
sellBalanceIdUuidrequiredbuyBalanceIdUuidrequiredsellAmountMoneyrequiredbuyAmountMoneyrequiredrateRaterequiredfixedSideFixedSiderequiredquoteIdUuidrequiredfeeMoney | nullsettlementDateDate | nulldepositMoney | nullremainingMoney | nullorderIdstringrequiredread-onlyHuman order id shown on confirmations.
providerRefstring | nullread-onlycreatedByUuid | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
completedAtTimestamp | nullpurposestringread-onlyWhat the conversion is for: a direct exchange, an add-money conversion order or the funding of a cross-currency payment.
statusReasonstring | nullread-onlyWhy the exchange failed or was cancelled.
marginCallobject | nullread-onlyOpen margin call on a forward: deposit top-up required (
POST /forward-contracts/{exchangeId}/deposit).drawdownCountintegerread-onlyDrawdowns requested on a forward or held-rate contract.
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+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/forward-contracts/{exchangeId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/forward-contracts/{exchangeId}", {
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/forward-contracts/{exchangeId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Top up a forward deposit (margin call)
POST /v1/forward-contracts/{exchangeId}/deposit
- topUpForwardDeposit
- API key scope exchanges:write
- Idempotency-Key required
- Tenant customer
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
Feature flag: fx.forwards; returns 404 with problem type feature-disabled when the flag is off for the operator.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
Deposit top-up for an open forward (margin call), in the contract's sell currency; taken from fromBalanceId (default: the sell balance). Clears the margin call when it covers it.
amountPositiveMoneyrequiredfromBalanceIdUuid | null
Responses
200 OK
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
kindExchangeKindrequiredstatusExchangeStatusrequiredread-onlyFields of status
sellBalanceIdUuidrequiredbuyBalanceIdUuidrequiredsellAmountMoneyrequiredbuyAmountMoneyrequiredrateRaterequiredfixedSideFixedSiderequiredquoteIdUuidrequiredfeeMoney | nullsettlementDateDate | nulldepositMoney | nullremainingMoney | nullorderIdstringrequiredread-onlyHuman order id shown on confirmations.
providerRefstring | nullread-onlycreatedByUuid | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
completedAtTimestamp | nullpurposestringread-onlyWhat the conversion is for: a direct exchange, an add-money conversion order or the funding of a cross-currency payment.
statusReasonstring | nullread-onlyWhy the exchange failed or was cancelled.
marginCallobject | nullread-onlyOpen margin call on a forward: deposit top-up required (
POST /forward-contracts/{exchangeId}/deposit).drawdownCountintegerread-onlyDrawdowns requested on a forward or held-rate contract.
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/forward-contracts/{exchangeId}/deposit" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
}'const response = await fetch("https://bank.wirebloom.com/v1/forward-contracts/{exchangeId}/deposit", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/forward-contracts/{exchangeId}/deposit",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
},
timeout=30,
)
response.raise_for_status()Draw down a forward contract
POST /v1/forward-contracts/{exchangeId}/drawdowns
- drawdownForwardContract
- API key scope exchanges:write
- Idempotency-Key required
- Tenant customer
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
Feature flag: fx.forwards; returns 404 with problem type feature-disabled when the flag is off for the operator.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
Use part of the remaining forward balance (settle to buy balance or fund a payment).
amountPositiveMoneyrequiredpaymentIdUuid | null
Responses
200 OK
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
kindExchangeKindrequiredstatusExchangeStatusrequiredread-onlyFields of status
sellBalanceIdUuidrequiredbuyBalanceIdUuidrequiredsellAmountMoneyrequiredbuyAmountMoneyrequiredrateRaterequiredfixedSideFixedSiderequiredquoteIdUuidrequiredfeeMoney | nullsettlementDateDate | nulldepositMoney | nullremainingMoney | nullorderIdstringrequiredread-onlyHuman order id shown on confirmations.
providerRefstring | nullread-onlycreatedByUuid | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
completedAtTimestamp | nullpurposestringread-onlyWhat the conversion is for: a direct exchange, an add-money conversion order or the funding of a cross-currency payment.
statusReasonstring | nullread-onlyWhy the exchange failed or was cancelled.
marginCallobject | nullread-onlyOpen margin call on a forward: deposit top-up required (
POST /forward-contracts/{exchangeId}/deposit).drawdownCountintegerread-onlyDrawdowns requested on a forward or held-rate contract.
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/forward-contracts/{exchangeId}/drawdowns" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
}'const response = await fetch("https://bank.wirebloom.com/v1/forward-contracts/{exchangeId}/drawdowns", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/forward-contracts/{exchangeId}/drawdowns",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"amount": {
"amountMinor": "125050",
"currency": "GBP"
}
},
timeout=30,
)
response.raise_for_status()Deposit balance held for forwards
GET /v1/forward-contracts/deposit-balance
- getForwardDepositBalance
- API key scope exchanges:read
- Tenant customer
Feature flag: fx.forwards; returns 404 with problem type feature-disabled when the flag is off for the operator.
API key scope: exchanges: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/jsonDeposits held against open forward contracts (Equals "View deposit balance").
balancesarray of objectrequiredFields of balances
currencyCurrencyCoderequiredheldMoneyrequiredcontractsintegerrequired
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+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/forward-contracts/deposit-balance" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/forward-contracts/deposit-balance", {
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/forward-contracts/deposit-balance",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()List funds requests
GET /v1/funds-requests
- listFundsRequests
- API key scope payments:read
- Tenant customer
API key scope: payments: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. |
cursor | query | string | Opaque cursor from |
limit | query | integer | Page size (max 100). |
sort | query | string | Sort order; prefix |
filter | query | object | Filters as |
Responses
200 OK
application/jsonCursor-paginated list of FundsRequest.
dataarray of FundsRequestrequiredpagePageInforequired
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+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/funds-requests" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/funds-requests", {
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/funds-requests",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Request funds
POST /v1/funds-requests
- createFundsRequest
- API key scope payments:write
- Idempotency-Key required
- Tenant customer
409 funds-requests-disabled when the customer setting is off.
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
balanceIdUuidrequiredamountPositiveMoneyrequiredreasonstringrequiredfromBalanceIdUuid | null
Responses
201 Created
application/jsonEquals "Requests": a member asks balance holders for funds (e.g. to a sub-balance or card). Fulfilment is an internal transfer (
transferId) intobalanceIdfrom the approver's chosen source.idUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
balanceIdUuidrequiredamountMoneyrequiredreasonstringrequiredstatusFundsRequestStatusrequiredread-onlyFields of status
approvalIdUuid | nullrequestedByUuidrequiredread-onlyFields of requestedBy
createdAtTimestamprequiredread-onlyFields of createdAt
decidedAtTimestamp | nullfromBalanceIdUuid | nulltransferIdUuid | nulldecisionReasonstring | nullread-onlyexpiresAtTimestamp | null
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/funds-requests" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"reason": "string"
}'const response = await fetch("https://bank.wirebloom.com/v1/funds-requests", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"reason": "string"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/funds-requests",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"reason": "string"
},
timeout=30,
)
response.raise_for_status()Get funds request
GET /v1/funds-requests/{fundsRequestId}
- getFundsRequest
- API key scope payments:read
- Tenant customer
API key scope: payments:read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
fundsRequestIdrequired | path | Uuid | Identifier (fundsRequestId). |
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/jsonEquals "Requests": a member asks balance holders for funds (e.g. to a sub-balance or card). Fulfilment is an internal transfer (
transferId) intobalanceIdfrom the approver's chosen source.idUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
balanceIdUuidrequiredamountMoneyrequiredreasonstringrequiredstatusFundsRequestStatusrequiredread-onlyFields of status
approvalIdUuid | nullrequestedByUuidrequiredread-onlyFields of requestedBy
createdAtTimestamprequiredread-onlyFields of createdAt
decidedAtTimestamp | nullfromBalanceIdUuid | nulltransferIdUuid | nulldecisionReasonstring | nullread-onlyexpiresAtTimestamp | null
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+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/funds-requests/{fundsRequestId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/funds-requests/{fundsRequestId}", {
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/funds-requests/{fundsRequestId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Cancel funds request
POST /v1/funds-requests/{fundsRequestId}/cancel
- cancelFundsRequest
- API key scope payments:write
- Tenant customer
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
fundsRequestIdrequired | path | Uuid | Identifier (fundsRequestId). |
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/jsonEquals "Requests": a member asks balance holders for funds (e.g. to a sub-balance or card). Fulfilment is an internal transfer (
transferId) intobalanceIdfrom the approver's chosen source.idUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
balanceIdUuidrequiredamountMoneyrequiredreasonstringrequiredstatusFundsRequestStatusrequiredread-onlyFields of status
approvalIdUuid | nullrequestedByUuidrequiredread-onlyFields of requestedBy
createdAtTimestamprequiredread-onlyFields of createdAt
decidedAtTimestamp | nullfromBalanceIdUuid | nulltransferIdUuid | nulldecisionReasonstring | nullread-onlyexpiresAtTimestamp | null
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/funds-requests/{fundsRequestId}/cancel" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/funds-requests/{fundsRequestId}/cancel", {
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/funds-requests/{fundsRequestId}/cancel",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()List direct debit mandates
GET /v1/mandates
- listMandates
- API key scope payments:read
- Tenant customer
Feature flag: payments.direct_debits; returns 404 with problem type feature-disabled when the flag is off for the operator.
API key scope: payments: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. |
cursor | query | string | Opaque cursor from |
limit | query | integer | Page size (max 100). |
sort | query | string | Sort order; prefix |
filter | query | object | Filters as |
Responses
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+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/mandates" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/mandates", {
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/mandates",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Create mandate
POST /v1/mandates
- createMandate
- API key scope payments:write
- Idempotency-Key required
- Tenant customer
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
Feature flag: payments.direct_debits; returns 404 with problem type feature-disabled when the flag is off for the operator.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
directionMandateDirectionrequiredschemeMandateSchemerequiredreferencestringrequiredMandate reference (UMR); empty generates one (
WB+ 14 characters).balanceIdUuidrequiredcounterpartyobjectrequiredFields of counterparty
namestringrequiredibanstring | nullaccountNumberstring | nullsortCodestring | nullbicstring | nullcreditorIdstring | nulladdressAddress | null
signedAtDate | nullmandateDocumentIdUuid | null
Responses
201 Created
application/jsonCounterparty account identifiers are returned masked.
idUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
directionMandateDirectionrequiredschemeMandateSchemerequiredreferencestringrequiredbalanceIdUuidrequiredcounterpartyobjectrequiredFields of counterparty
namestringrequiredibanstring | nullaccountNumberstring | nullsortCodestring | nullbicstring | nullcreditorIdstring | nulladdressAddress | null
statusMandateStatusrequiredread-onlyFields of status
signedAtTimestamp | nullcancelledAtTimestamp | nullproviderRefstring | nullread-onlycreatedAtTimestamprequiredread-onlyFields of createdAt
managementstringread-onlyclient: WireBloom generates collection files / status reports are entered by staff;provider: the partner manages the mandate.statusReasonstring | nullread-onlylastCollectionAtTimestamp | null
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/mandates" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"direction": "collect",
"scheme": "sepa_dd_core",
"reference": "string",
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"counterparty": {
"name": "string"
}
}'const response = await fetch("https://bank.wirebloom.com/v1/mandates", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"direction": "collect",
"scheme": "sepa_dd_core",
"reference": "string",
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"counterparty": {
"name": "string"
}
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/mandates",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"direction": "collect",
"scheme": "sepa_dd_core",
"reference": "string",
"balanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"counterparty": {
"name": "string"
}
},
timeout=30,
)
response.raise_for_status()Get mandate
GET /v1/mandates/{mandateId}
- getMandate
- API key scope payments:read
- Tenant customer
Feature flag: payments.direct_debits; returns 404 with problem type feature-disabled when the flag is off for the operator.
API key scope: payments:read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
mandateIdrequired | path | Uuid | Identifier (mandateId). |
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/jsonCounterparty account identifiers are returned masked.
idUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
directionMandateDirectionrequiredschemeMandateSchemerequiredreferencestringrequiredbalanceIdUuidrequiredcounterpartyobjectrequiredFields of counterparty
namestringrequiredibanstring | nullaccountNumberstring | nullsortCodestring | nullbicstring | nullcreditorIdstring | nulladdressAddress | null
statusMandateStatusrequiredread-onlyFields of status
signedAtTimestamp | nullcancelledAtTimestamp | nullproviderRefstring | nullread-onlycreatedAtTimestamprequiredread-onlyFields of createdAt
managementstringread-onlyclient: WireBloom generates collection files / status reports are entered by staff;provider: the partner manages the mandate.statusReasonstring | nullread-onlylastCollectionAtTimestamp | null
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+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/mandates/{mandateId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/mandates/{mandateId}", {
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/mandates/{mandateId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Cancel mandate
POST /v1/mandates/{mandateId}/cancel
- cancelMandate
- API key scope payments:write
- Tenant customer
Feature flag: payments.direct_debits; returns 404 with problem type feature-disabled when the flag is off for the operator.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
mandateIdrequired | path | Uuid | Identifier (mandateId). |
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. |
Request body
reasonstring | null
Responses
200 OK
application/jsonCounterparty account identifiers are returned masked.
idUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
directionMandateDirectionrequiredschemeMandateSchemerequiredreferencestringrequiredbalanceIdUuidrequiredcounterpartyobjectrequiredFields of counterparty
namestringrequiredibanstring | nullaccountNumberstring | nullsortCodestring | nullbicstring | nullcreditorIdstring | nulladdressAddress | null
statusMandateStatusrequiredread-onlyFields of status
signedAtTimestamp | nullcancelledAtTimestamp | nullproviderRefstring | nullread-onlycreatedAtTimestamprequiredread-onlyFields of createdAt
managementstringread-onlyclient: WireBloom generates collection files / status reports are entered by staff;provider: the partner manages the mandate.statusReasonstring | nullread-onlylastCollectionAtTimestamp | null
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/mandates/{mandateId}/cancel" \
-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/mandates/{mandateId}/cancel", {
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/mandates/{mandateId}/cancel",
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()Collection schedules of a mandate
GET /v1/mandates/{mandateId}/schedules
- listMandateSchedules
- API key scope payments:read
- Tenant customer
Activate, deactivate or end them through /scheduled-payments/{scheduledPaymentId}.
Feature flag: payments.direct_debits; returns 404 with problem type feature-disabled when the flag is off for the operator.
API key scope: payments:read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
mandateIdrequired | path | Uuid | Identifier (mandateId). |
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/jsondataarray of ScheduledPaymentrequired
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+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/mandates/{mandateId}/schedules" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/mandates/{mandateId}/schedules", {
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/mandates/{mandateId}/schedules",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Create a collection schedule
POST /v1/mandates/{mandateId}/schedules
- createMandateSchedule
- API key scope payments:write
- Idempotency-Key required
- Tenant customer
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
Feature flag: payments.direct_debits; returns 404 with problem type feature-disabled when the flag is off for the operator.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
mandateIdrequired | path | Uuid | Identifier (mandateId). |
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
namestring | nullamountPositiveMoneyrequiredreferencestring | nullscheduleobjectrequired
Responses
201 Created
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
namestring | nulltemplateScheduledPaymentTemplate | CollectionScheduleTemplaterequiredscheduleobjectrequiredstatusScheduledPaymentStatusrequiredread-onlyFields of status
nextRunAtTimestamp | nulllastPaymentIdUuid | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
updatedAtTimestampread-onlyFields of updatedAt
kindstringread-onlynextExecutionDateDate | nullconsecutiveFailuresintegerread-onlyFailed runs in a row; three deactivate the schedule.
preApprovedbooleanread-onlyRuns skip the approval tier (operator setting
payments.scheduled.preApproveStandingOrders, approved at creation).statusReasonstring | nullread-only
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/mandates/{mandateId}/schedules" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"schedule": {
"rrule": "string",
"startDate": "2026-09-30"
}
}'const response = await fetch("https://bank.wirebloom.com/v1/mandates/{mandateId}/schedules", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"schedule": {
"rrule": "string",
"startDate": "2026-09-30"
}
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/mandates/{mandateId}/schedules",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"schedule": {
"rrule": "string",
"startDate": "2026-09-30"
}
},
timeout=30,
)
response.raise_for_status()Record the mandate signature
POST /v1/mandates/{mandateId}/sign
- signMandate
- API key scope payments:write
- Tenant customer
Feature flag: payments.direct_debits; returns 404 with problem type feature-disabled when the flag is off for the operator.
API key scope: payments:write.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
mandateIdrequired | path | Uuid | Identifier (mandateId). |
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. |
Request body
Records the debtor's signature of a pending mandate (pending → active).
Responses
200 OK
application/jsonCounterparty account identifiers are returned masked.
idUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
directionMandateDirectionrequiredschemeMandateSchemerequiredreferencestringrequiredbalanceIdUuidrequiredcounterpartyobjectrequiredFields of counterparty
namestringrequiredibanstring | nullaccountNumberstring | nullsortCodestring | nullbicstring | nullcreditorIdstring | nulladdressAddress | null
statusMandateStatusrequiredread-onlyFields of status
signedAtTimestamp | nullcancelledAtTimestamp | nullproviderRefstring | nullread-onlycreatedAtTimestamprequiredread-onlyFields of createdAt
managementstringread-onlyclient: WireBloom generates collection files / status reports are entered by staff;provider: the partner manages the mandate.statusReasonstring | nullread-onlylastCollectionAtTimestamp | null
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/mandates/{mandateId}/sign" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"signedAt": "2026-09-30"
}'const response = await fetch("https://bank.wirebloom.com/v1/mandates/{mandateId}/sign", {
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({
"signedAt": "2026-09-30"
}),
});
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/mandates/{mandateId}/sign",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"signedAt": "2026-09-30"
},
timeout=30,
)
response.raise_for_status()List payments
GET /v1/payments
- listPayments
- API key scope payments:read
- Tenant customer
API key scope: payments:read.
Metadata filter: filter[metadata.<key>]=<value> (exact match; at most 5; AND).
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. |
cursor | query | string | Opaque cursor from |
limit | query | integer | Page size (max 100). |
sort | query | string | Sort order; prefix |
filter | query | object | Filters as |
q | query | string | Free-text search (trigram; min 2 characters). |
Responses
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+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/payments" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/payments", {
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/payments",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Create payment (single-payment wizard)
POST /v1/payments
- createPayment
- API key scope payments:write
- Idempotency-Key required
- Tenant customer
Validates limits and balance, computes fees, places a hold, applies approval tiers (→ pending_approval) or routes and submits. Conditional step-up: x-step-up names payment.first_to_recipient, but the requirement is evaluated after validation: the first payment to a recipient needs payment.first_to_recipient, a payment at or above the threshold (customer settings.payments.stepUpThreshold, else operator payments.stepUpThreshold) needs payment.above_threshold; drafts (submit: false) need none. POST /payments/dry-run returns requiresStepUp / stepUpAction. API-key requests skip step-up but are always subject to approval tiers (D-24). Recipient must be approved. Cross-currency payments (amount.currency ≠ source currency) need a live spot quoteId selling the source currency for exactly amount (422 quote_required / quote_mismatch, 409 quote-expired); the conversion executes before submission.
Step-up: requires a verified step-up challenge for action payment.first_to_recipient within the last 5 minutes (session/bearer only). Otherwise 403 with problem type step-up-required; the step-up check runs before body validation.
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
Single-payment wizard: recipient → amount/currency → reference/purpose/attachments → date → review → submit. When amount.currency differs from the source balance, pass a live quoteId (or fixedSide to let the server quote).
sourceBalanceIdUuidrequiredrecipientIdUuidrequiredamountPositiveMoneyrequiredfixedSideFixedSidequoteIdUuid | nullreferencestringrequiredpurposeCodestring | nullPurpose / transfer reason from
GET /payments/purpose-codes(ISO 20022ExternalPurpose1Code; CNH needsGOD,STR,CTForOTF:422 purpose_required/invalid_purpose).chargeBearerChargeBearer | nullurgentbooleanscheduledForDate | nullattachmentDocumentIdsarray of Uuidsubmitbooleanfalsesaves a draft;truesubmits (approval, holds, routing).notestring | nullmetadataMetadata
Responses
201 Created
application/jsonOutgoing payment.
amountis what the recipient receives (recipient currency);sendAmountis debited from the source balance when currencies differ.idUuidrequiredread-onlyAlso used as the provider idempotency key.
Fields of id
customerIdUuidrequiredread-onlyFields of customerId
kindPaymentKindrequiredread-onlyFields of kind
statusPaymentStatusrequiredread-onlyFields of status
statusReasonstring | nullread-onlysourceBalanceIdUuidrequiredrecipientIdUuid | nullrecipientPaymentParty | nullamountMoneyrequiredsendAmountMoney | nullquoteIdUuid | nullrateRate | nullfeesarray of FeeLinerequiredread-onlytotalDebitMoneyrequiredread-onlyFields of totalDebit
amountMinorAmountMinorrequiredcurrencyCurrencyCoderequired
railRailrequiredread-onlyFields of rail
referencestringrequiredpurposeCodestring | nullchargeBearerChargeBearer | nullurgentbooleanrequiredscheduledForDate | nullestimatedArrivalTimestamp | nullattachmentDocumentIdsarray of Uuidapprovalobject | nullread-onlyFields of approval
approvalIdUuidrequiredApprovalsintegerapprovalsReceivedintegerstatusApprovalStatus
providerRefstring | nullread-onlyProvider reference (e.g. UETR for SWIFT).
channelChannelrequiredread-onlyFields of channel
createdByUuidread-onlyFields of createdBy
apiKeyIdUuid | nullsubmittedAtTimestamp | nullcompletedAtTimestamp | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
updatedAtTimestampread-onlyFields of updatedAt
transactionIdUuid | nullmetadataMetadataprocessingPaymentProcessing
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/payments" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"sourceBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"recipientId": "0192a6f1-2222-7000-8000-00000000a001",
"amount": {
"amountMinor": "100000",
"currency": "EUR"
},
"fixedSide": "buy",
"quoteId": "0192a6f1-4444-7000-8000-00000000d001",
"reference": "INV-2026-0042",
"submit": true
}'const response = await fetch("https://bank.wirebloom.com/v1/payments", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"sourceBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"recipientId": "0192a6f1-2222-7000-8000-00000000a001",
"amount": {
"amountMinor": "100000",
"currency": "EUR"
},
"fixedSide": "buy",
"quoteId": "0192a6f1-4444-7000-8000-00000000d001",
"reference": "INV-2026-0042",
"submit": true
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/payments",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"sourceBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"recipientId": "0192a6f1-2222-7000-8000-00000000a001",
"amount": {
"amountMinor": "100000",
"currency": "EUR"
},
"fixedSide": "buy",
"quoteId": "0192a6f1-4444-7000-8000-00000000d001",
"reference": "INV-2026-0042",
"submit": True
},
timeout=30,
)
response.raise_for_status()Get payment
GET /v1/payments/{paymentId}
- getPayment
- API key scope payments:read
- Tenant customer
API key scope: payments:read.
Processing with ETA (D-50): while an approved payment waits in the submission queue behind other payments of the operator, processing gives its queue position and an estimated hand-off time; it is absent once the payment is submitted (and for scheduled payments before their execution date).
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. |
If-None-Match | header | string | Conditional GET; |
Responses
200 OK
application/jsonOutgoing payment.
amountis what the recipient receives (recipient currency);sendAmountis debited from the source balance when currencies differ.idUuidrequiredread-onlyAlso used as the provider idempotency key.
Fields of id
customerIdUuidrequiredread-onlyFields of customerId
kindPaymentKindrequiredread-onlyFields of kind
statusPaymentStatusrequiredread-onlyFields of status
statusReasonstring | nullread-onlysourceBalanceIdUuidrequiredrecipientIdUuid | nullrecipientPaymentParty | nullamountMoneyrequiredsendAmountMoney | nullquoteIdUuid | nullrateRate | nullfeesarray of FeeLinerequiredread-onlytotalDebitMoneyrequiredread-onlyFields of totalDebit
amountMinorAmountMinorrequiredcurrencyCurrencyCoderequired
railRailrequiredread-onlyFields of rail
referencestringrequiredpurposeCodestring | nullchargeBearerChargeBearer | nullurgentbooleanrequiredscheduledForDate | nullestimatedArrivalTimestamp | nullattachmentDocumentIdsarray of Uuidapprovalobject | nullread-onlyFields of approval
approvalIdUuidrequiredApprovalsintegerapprovalsReceivedintegerstatusApprovalStatus
providerRefstring | nullread-onlyProvider reference (e.g. UETR for SWIFT).
channelChannelrequiredread-onlyFields of channel
createdByUuidread-onlyFields of createdBy
apiKeyIdUuid | nullsubmittedAtTimestamp | nullcompletedAtTimestamp | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
updatedAtTimestampread-onlyFields of updatedAt
transactionIdUuid | nullmetadataMetadataprocessingPaymentProcessing
304 Not modified (`If-None-Match` matched).
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+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/payments/{paymentId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/payments/{paymentId}", {
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/payments/{paymentId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Edit draft payment
PATCH /v1/payments/{paymentId}
- updatePaymentDraft
- API key scope payments:write
- Tenant customer
Concurrency: If-Match with the current ETag is required (428 if absent, 412 if stale).
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. |
If-Matchrequired | header | string | ETag of the representation being modified (from a prior GET/PATCH). |
Request body
Only draft payments are editable.
amountPositiveMoneyquoteIdUuid | nullreferencestringpurposeCodestring | nullPurpose / transfer reason from
GET /payments/purpose-codes(ISO 20022ExternalPurpose1Code; CNH needsGOD,STR,CTForOTF:422 purpose_required/invalid_purpose).chargeBearerChargeBearer | nullurgentbooleanscheduledForDate | nullattachmentDocumentIdsarray of UuidmetadataMetadataPatch
Responses
200 OK
application/jsonOutgoing payment.
amountis what the recipient receives (recipient currency);sendAmountis debited from the source balance when currencies differ.idUuidrequiredread-onlyAlso used as the provider idempotency key.
Fields of id
customerIdUuidrequiredread-onlyFields of customerId
kindPaymentKindrequiredread-onlyFields of kind
statusPaymentStatusrequiredread-onlyFields of status
statusReasonstring | nullread-onlysourceBalanceIdUuidrequiredrecipientIdUuid | nullrecipientPaymentParty | nullamountMoneyrequiredsendAmountMoney | nullquoteIdUuid | nullrateRate | nullfeesarray of FeeLinerequiredread-onlytotalDebitMoneyrequiredread-onlyFields of totalDebit
amountMinorAmountMinorrequiredcurrencyCurrencyCoderequired
railRailrequiredread-onlyFields of rail
referencestringrequiredpurposeCodestring | nullchargeBearerChargeBearer | nullurgentbooleanrequiredscheduledForDate | nullestimatedArrivalTimestamp | nullattachmentDocumentIdsarray of Uuidapprovalobject | nullread-onlyFields of approval
approvalIdUuidrequiredApprovalsintegerapprovalsReceivedintegerstatusApprovalStatus
providerRefstring | nullread-onlyProvider reference (e.g. UETR for SWIFT).
channelChannelrequiredread-onlyFields of channel
createdByUuidread-onlyFields of createdBy
apiKeyIdUuid | nullsubmittedAtTimestamp | nullcompletedAtTimestamp | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
updatedAtTimestampread-onlyFields of updatedAt
transactionIdUuid | nullmetadataMetadataprocessingPaymentProcessing
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+json412 `If-Match` does not match the current ETag (resource changed).
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+json428 `If-Match` header is required for this operation.
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 PATCH "https://bank.wirebloom.com/v1/payments/{paymentId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "If-Match: \"<etag>\"" \
-H "Content-Type: application/json" \
--data '{}'const response = await fetch("https://bank.wirebloom.com/v1/payments/{paymentId}", {
method: "PATCH",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"If-Match": "\"<etag>\"",
"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(
"PATCH",
"https://bank.wirebloom.com/v1/payments/{paymentId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"If-Match": "\"<etag>\"",
"Content-Type": "application/json",
},
json={},
timeout=30,
)
response.raise_for_status()Cancel payment (before submission)
POST /v1/payments/{paymentId}/cancel
- cancelPayment
- API key scope payments:write
- Tenant customer
Allowed in draft, pending_approval, approved and scheduled; releases the hold. After submission use a recall via operator support (409 not-cancellable).
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
reasonstring | null
Responses
200 OK
application/jsonOutgoing payment.
amountis what the recipient receives (recipient currency);sendAmountis debited from the source balance when currencies differ.idUuidrequiredread-onlyAlso used as the provider idempotency key.
Fields of id
customerIdUuidrequiredread-onlyFields of customerId
kindPaymentKindrequiredread-onlyFields of kind
statusPaymentStatusrequiredread-onlyFields of status
statusReasonstring | nullread-onlysourceBalanceIdUuidrequiredrecipientIdUuid | nullrecipientPaymentParty | nullamountMoneyrequiredsendAmountMoney | nullquoteIdUuid | nullrateRate | nullfeesarray of FeeLinerequiredread-onlytotalDebitMoneyrequiredread-onlyFields of totalDebit
amountMinorAmountMinorrequiredcurrencyCurrencyCoderequired
railRailrequiredread-onlyFields of rail
referencestringrequiredpurposeCodestring | nullchargeBearerChargeBearer | nullurgentbooleanrequiredscheduledForDate | nullestimatedArrivalTimestamp | nullattachmentDocumentIdsarray of Uuidapprovalobject | nullread-onlyFields of approval
approvalIdUuidrequiredApprovalsintegerapprovalsReceivedintegerstatusApprovalStatus
providerRefstring | nullread-onlyProvider reference (e.g. UETR for SWIFT).
channelChannelrequiredread-onlyFields of channel
createdByUuidread-onlyFields of createdBy
apiKeyIdUuid | nullsubmittedAtTimestamp | nullcompletedAtTimestamp | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
updatedAtTimestampread-onlyFields of updatedAt
transactionIdUuid | nullmetadataMetadataprocessingPaymentProcessing
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/payments/{paymentId}/cancel" \
-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/payments/{paymentId}/cancel", {
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/payments/{paymentId}/cancel",
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()Payment order confirmation (PDF)
GET /v1/payments/{paymentId}/confirmation
- getPaymentConfirmation
- API key scope statements:read
- Tenant customer
API key scope: statements:read.
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. |
Responses
200 OK
application/pdf401 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+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/payments/{paymentId}/confirmation" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/payments/{paymentId}/confirmation", {
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/payments/{paymentId}/confirmation",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Payment status history
GET /v1/payments/{paymentId}/events
- listPaymentEvents
- API key scope payments:read
- Tenant any
Payment timeline. Operator staff (x-tenant: any): with X-Tenant-Id set to a customer they read that customer; with their operator id they read every customer of the operator (RLS operator scope); 404 when the payment is outside the tenant.
API key scope: payments:read.
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. |
Responses
200 OK
application/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+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/payments/{paymentId}/events" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/payments/{paymentId}/events", {
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/payments/{paymentId}/events",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Submit draft payment
POST /v1/payments/{paymentId}/submit
- submitPayment
- API key scope payments:write
- Idempotency-Key required
- Tenant customer
Same checks as a direct submit; step-up is conditional as on createPayment (payment.first_to_recipient or payment.above_threshold).
Step-up: requires a verified step-up challenge for action payment.first_to_recipient within the last 5 minutes (session/bearer only). Otherwise 403 with problem type step-up-required; the step-up check runs before body validation.
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Responses
200 OK
application/jsonOutgoing payment.
amountis what the recipient receives (recipient currency);sendAmountis debited from the source balance when currencies differ.idUuidrequiredread-onlyAlso used as the provider idempotency key.
Fields of id
customerIdUuidrequiredread-onlyFields of customerId
kindPaymentKindrequiredread-onlyFields of kind
statusPaymentStatusrequiredread-onlyFields of status
statusReasonstring | nullread-onlysourceBalanceIdUuidrequiredrecipientIdUuid | nullrecipientPaymentParty | nullamountMoneyrequiredsendAmountMoney | nullquoteIdUuid | nullrateRate | nullfeesarray of FeeLinerequiredread-onlytotalDebitMoneyrequiredread-onlyFields of totalDebit
amountMinorAmountMinorrequiredcurrencyCurrencyCoderequired
railRailrequiredread-onlyFields of rail
referencestringrequiredpurposeCodestring | nullchargeBearerChargeBearer | nullurgentbooleanrequiredscheduledForDate | nullestimatedArrivalTimestamp | nullattachmentDocumentIdsarray of Uuidapprovalobject | nullread-onlyFields of approval
approvalIdUuidrequiredApprovalsintegerapprovalsReceivedintegerstatusApprovalStatus
providerRefstring | nullread-onlyProvider reference (e.g. UETR for SWIFT).
channelChannelrequiredread-onlyFields of channel
createdByUuidread-onlyFields of createdBy
apiKeyIdUuid | nullsubmittedAtTimestamp | nullcompletedAtTimestamp | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
updatedAtTimestampread-onlyFields of updatedAt
transactionIdUuid | nullmetadataMetadataprocessingPaymentProcessing
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/payments/{paymentId}/submit" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)"const response = await fetch("https://bank.wirebloom.com/v1/payments/{paymentId}/submit", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
},
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/payments/{paymentId}/submit",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
},
timeout=30,
)
response.raise_for_status()Preview fees, rate, route and checks
POST /v1/payments/dry-run
- dryRunPayment
- API key scope payments:write
- Tenant customer
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. |
Request body
Single-payment wizard: recipient → amount/currency → reference/purpose/attachments → date → review → submit. When amount.currency differs from the source balance, pass a live quoteId (or fixedSide to let the server quote).
sourceBalanceIdUuidrequiredrecipientIdUuidrequiredamountPositiveMoneyrequiredfixedSideFixedSidequoteIdUuid | nullreferencestringrequiredpurposeCodestring | nullPurpose / transfer reason from
GET /payments/purpose-codes(ISO 20022ExternalPurpose1Code; CNH needsGOD,STR,CTForOTF:422 purpose_required/invalid_purpose).chargeBearerChargeBearer | nullurgentbooleanscheduledForDate | nullattachmentDocumentIdsarray of Uuidsubmitbooleanfalsesaves a draft;truesubmits (approval, holds, routing).notestring | nullmetadataMetadata
Responses
200 OK
application/jsonFees, route and checks preview for the Review step. No holds, no side effects.
railRailrequiredconnectionNamestring | nullShown to staff only.
amountMoneyrequiredsendAmountMoneyrequiredrateRate | nullquoteIdUuid | nullquoteExpiresAtTimestamp | nullfeesarray of FeeLinerequiredtotalDebitMoneyrequiredestimatedArrivalTimestamprequiredearliestExecutionDateDaterequiredcutOffTimestamp | nullrequiresApprovalbooleanrequiredrequiresStepUpbooleanrequiredstepUpActionStepUpAction | nulllimitCheckobjectrequiredFields of limitCheck
withinLimitsbooleanbreachesarray of objectFields of breaches
limitstringremainingMoney
warningsarray of objectrequiredFields of warnings
codestringmessagestring
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/payments/dry-run" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"sourceBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"recipientId": "0192a6f1-2222-7000-8000-00000000a001",
"amount": {
"amountMinor": "100000",
"currency": "EUR"
},
"fixedSide": "buy",
"quoteId": "0192a6f1-4444-7000-8000-00000000d001",
"reference": "INV-2026-0042",
"purposeCode": "SUPP",
"urgent": false,
"submit": true
}'const response = await fetch("https://bank.wirebloom.com/v1/payments/dry-run", {
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({
"sourceBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"recipientId": "0192a6f1-2222-7000-8000-00000000a001",
"amount": {
"amountMinor": "100000",
"currency": "EUR"
},
"fixedSide": "buy",
"quoteId": "0192a6f1-4444-7000-8000-00000000d001",
"reference": "INV-2026-0042",
"purposeCode": "SUPP",
"urgent": false,
"submit": true
}),
});
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/payments/dry-run",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"sourceBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"recipientId": "0192a6f1-2222-7000-8000-00000000a001",
"amount": {
"amountMinor": "100000",
"currency": "EUR"
},
"fixedSide": "buy",
"quoteId": "0192a6f1-4444-7000-8000-00000000d001",
"reference": "INV-2026-0042",
"purposeCode": "SUPP",
"urgent": False,
"submit": True
},
timeout=30,
)
response.raise_for_status()Purpose codes for a payment
GET /v1/payments/purpose-codes
- listPurposeCodes
- API key scope payments:read
- Tenant any
Purpose / transfer-reason catalogue (P10-T03, FR-PAY-13, parity P-50) for a currency, destination and rail: the accepted codes and whether one is required. Payment creation applies the same rule.
API key scope: payments: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. |
currencyrequired | query | CurrencyCode | Payment currency. |
country | query | CountryCode | Bank country of the recipient. |
rail | query | Rail | Rail, when known. |
Responses
200 OK
application/jsoncurrencyCurrencyCoderequiredcountryCountryCode | nullrequiredrailRail | nullrequiredrequiredbooleanrequiredA purpose code must be sent with payments in this context (e.g. CNH).
reasonstring | nullrequiredcodesarray of PurposeCoderequiredroutingCodestring | nullrequiredDomestic routing code the destination needs (
aba,transit,clabe,bsb,ifsc,cnaps,sortCode); null for IBAN countries.railLabelstring | nullrequired
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+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/payments/purpose-codes?currency=GBP" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/payments/purpose-codes?currency=GBP", {
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/payments/purpose-codes?currency=GBP",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()List scheduled payments (Active / Inactive)
GET /v1/scheduled-payments
- listScheduledPayments
- API key scope payments:read
- Tenant customer
API key scope: payments: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. |
cursor | query | string | Opaque cursor from |
limit | query | integer | Page size (max 100). |
sort | query | string | Sort order; prefix |
filter | query | object | Filters as |
withTotal | query | boolean | Include |
Responses
200 OK
application/jsonCursor-paginated list of ScheduledPayment.
dataarray of ScheduledPaymentrequiredpagePageInforequired
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+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/scheduled-payments" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/scheduled-payments", {
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/scheduled-payments",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Create scheduled payment / standing order
POST /v1/scheduled-payments
- createScheduledPayment
- API key scope payments:write
- Idempotency-Key required
- Tenant customer
Step-up: requires a verified step-up challenge for action payment.first_to_recipient within the last 5 minutes (session/bearer only). Otherwise 403 with problem type step-up-required; the step-up check runs before body validation.
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
namestring | nulltemplateobjectrequiredFields of template
sourceBalanceIdUuidrequiredrecipientIdUuidrequiredamountPositiveMoneyrequiredreferencestringrequiredpurposeCodestring | null
scheduleobjectrequired
Responses
201 Created
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
namestring | nulltemplateScheduledPaymentTemplate | CollectionScheduleTemplaterequiredscheduleobjectrequiredstatusScheduledPaymentStatusrequiredread-onlyFields of status
nextRunAtTimestamp | nulllastPaymentIdUuid | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
updatedAtTimestampread-onlyFields of updatedAt
kindstringread-onlynextExecutionDateDate | nullconsecutiveFailuresintegerread-onlyFailed runs in a row; three deactivate the schedule.
preApprovedbooleanread-onlyRuns skip the approval tier (operator setting
payments.scheduled.preApproveStandingOrders, approved at creation).statusReasonstring | nullread-only
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/scheduled-payments" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"template": {
"sourceBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"recipientId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"reference": "string"
},
"schedule": {
"rrule": "string",
"startDate": "2026-09-30"
}
}'const response = await fetch("https://bank.wirebloom.com/v1/scheduled-payments", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"template": {
"sourceBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"recipientId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"reference": "string"
},
"schedule": {
"rrule": "string",
"startDate": "2026-09-30"
}
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/scheduled-payments",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"template": {
"sourceBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"recipientId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"reference": "string"
},
"schedule": {
"rrule": "string",
"startDate": "2026-09-30"
}
},
timeout=30,
)
response.raise_for_status()Get scheduled payment
GET /v1/scheduled-payments/{scheduledPaymentId}
- getScheduledPayment
- API key scope payments:read
- Tenant customer
API key scope: payments:read.
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. |
If-None-Match | header | string | Conditional GET; |
Responses
200 OK
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
namestring | nulltemplateScheduledPaymentTemplate | CollectionScheduleTemplaterequiredscheduleobjectrequiredstatusScheduledPaymentStatusrequiredread-onlyFields of status
nextRunAtTimestamp | nulllastPaymentIdUuid | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
updatedAtTimestampread-onlyFields of updatedAt
kindstringread-onlynextExecutionDateDate | nullconsecutiveFailuresintegerread-onlyFailed runs in a row; three deactivate the schedule.
preApprovedbooleanread-onlyRuns skip the approval tier (operator setting
payments.scheduled.preApproveStandingOrders, approved at creation).statusReasonstring | nullread-only
304 Not modified (`If-None-Match` matched).
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+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/scheduled-payments/{scheduledPaymentId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/scheduled-payments/{scheduledPaymentId}", {
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/scheduled-payments/{scheduledPaymentId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Edit scheduled payment
PATCH /v1/scheduled-payments/{scheduledPaymentId}
- updateScheduledPayment
- API key scope payments:write
- Tenant customer
Concurrency: If-Match with the current ETag is required (428 if absent, 412 if stale).
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. |
If-Matchrequired | header | string | ETag of the representation being modified (from a prior GET/PATCH). |
Request body
namestring | nulltemplateobjectrequiredFields of template
sourceBalanceIdUuidrequiredrecipientIdUuidrequiredamountPositiveMoneyrequiredreferencestringrequiredpurposeCodestring | null
scheduleobjectrequired
Responses
200 OK
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
namestring | nulltemplateScheduledPaymentTemplate | CollectionScheduleTemplaterequiredscheduleobjectrequiredstatusScheduledPaymentStatusrequiredread-onlyFields of status
nextRunAtTimestamp | nulllastPaymentIdUuid | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
updatedAtTimestampread-onlyFields of updatedAt
kindstringread-onlynextExecutionDateDate | nullconsecutiveFailuresintegerread-onlyFailed runs in a row; three deactivate the schedule.
preApprovedbooleanread-onlyRuns skip the approval tier (operator setting
payments.scheduled.preApproveStandingOrders, approved at creation).statusReasonstring | nullread-only
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+json412 `If-Match` does not match the current ETag (resource changed).
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+json428 `If-Match` header is required for this operation.
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 PATCH "https://bank.wirebloom.com/v1/scheduled-payments/{scheduledPaymentId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "If-Match: \"<etag>\"" \
-H "Content-Type: application/json" \
--data '{
"template": {
"sourceBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"recipientId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"reference": "string"
},
"schedule": {
"rrule": "string",
"startDate": "2026-09-30"
}
}'const response = await fetch("https://bank.wirebloom.com/v1/scheduled-payments/{scheduledPaymentId}", {
method: "PATCH",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"If-Match": "\"<etag>\"",
"Content-Type": "application/json",
},
body: JSON.stringify({
"template": {
"sourceBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"recipientId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"reference": "string"
},
"schedule": {
"rrule": "string",
"startDate": "2026-09-30"
}
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os
import requests
response = requests.request(
"PATCH",
"https://bank.wirebloom.com/v1/scheduled-payments/{scheduledPaymentId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"If-Match": "\"<etag>\"",
"Content-Type": "application/json",
},
json={
"template": {
"sourceBalanceId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"recipientId": "0192a6f0-7c1e-7b3a-9d2e-5f4c3b2a1908",
"amount": {
"amountMinor": "125050",
"currency": "GBP"
},
"reference": "string"
},
"schedule": {
"rrule": "string",
"startDate": "2026-09-30"
}
},
timeout=30,
)
response.raise_for_status()End scheduled payment
DELETE /v1/scheduled-payments/{scheduledPaymentId}
- deleteScheduledPayment
- API key scope payments:write
- Tenant customer
Concurrency: If-Match with the current ETag is required (428 if absent, 412 if stale).
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. |
If-Matchrequired | header | string | ETag of the representation being modified (from a prior GET/PATCH). |
Responses
204 No Content
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+json412 `If-Match` does not match the current ETag (resource changed).
application/problem+json428 `If-Match` header is required for this operation.
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 DELETE "https://bank.wirebloom.com/v1/scheduled-payments/{scheduledPaymentId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "If-Match: \"<etag>\""const response = await fetch("https://bank.wirebloom.com/v1/scheduled-payments/{scheduledPaymentId}", {
method: "DELETE",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"If-Match": "\"<etag>\"",
},
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);import os
import requests
response = requests.request(
"DELETE",
"https://bank.wirebloom.com/v1/scheduled-payments/{scheduledPaymentId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"If-Match": "\"<etag>\"",
},
timeout=30,
)
response.raise_for_status()Reactivate
POST /v1/scheduled-payments/{scheduledPaymentId}/activate
- activateScheduledPayment
- API key scope payments:write
- Tenant customer
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. |
Responses
200 OK
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
namestring | nulltemplateScheduledPaymentTemplate | CollectionScheduleTemplaterequiredscheduleobjectrequiredstatusScheduledPaymentStatusrequiredread-onlyFields of status
nextRunAtTimestamp | nulllastPaymentIdUuid | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
updatedAtTimestampread-onlyFields of updatedAt
kindstringread-onlynextExecutionDateDate | nullconsecutiveFailuresintegerread-onlyFailed runs in a row; three deactivate the schedule.
preApprovedbooleanread-onlyRuns skip the approval tier (operator setting
payments.scheduled.preApproveStandingOrders, approved at creation).statusReasonstring | nullread-only
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/scheduled-payments/{scheduledPaymentId}/activate" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/scheduled-payments/{scheduledPaymentId}/activate", {
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/scheduled-payments/{scheduledPaymentId}/activate",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Deactivate
POST /v1/scheduled-payments/{scheduledPaymentId}/deactivate
- deactivateScheduledPayment
- API key scope payments:write
- Tenant customer
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. |
Responses
200 OK
application/jsonidUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
namestring | nulltemplateScheduledPaymentTemplate | CollectionScheduleTemplaterequiredscheduleobjectrequiredstatusScheduledPaymentStatusrequiredread-onlyFields of status
nextRunAtTimestamp | nulllastPaymentIdUuid | nullcreatedAtTimestamprequiredread-onlyFields of createdAt
updatedAtTimestampread-onlyFields of updatedAt
kindstringread-onlynextExecutionDateDate | nullconsecutiveFailuresintegerread-onlyFailed runs in a row; three deactivate the schedule.
preApprovedbooleanread-onlyRuns skip the approval tier (operator setting
payments.scheduled.preApproveStandingOrders, approved at creation).statusReasonstring | nullread-only
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/scheduled-payments/{scheduledPaymentId}/deactivate" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/scheduled-payments/{scheduledPaymentId}/deactivate", {
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/scheduled-payments/{scheduledPaymentId}/deactivate",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Upcoming and past runs
GET /v1/scheduled-payments/{scheduledPaymentId}/occurrences
- listScheduledPaymentOccurrences
- API key scope payments:read
- Tenant customer
API key scope: payments:read.
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. |
limit | query | integer | Upcoming runs to plan. |
Responses
200 OK
application/jsonupcomingarray of PlannedRunrequiredhistoryarray of ScheduledOccurrencerequired
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+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/scheduled-payments/{scheduledPaymentId}/occurrences" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/scheduled-payments/{scheduledPaymentId}/occurrences", {
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/scheduled-payments/{scheduledPaymentId}/occurrences",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Preview the runs of a schedule
POST /v1/scheduled-payments/preview
- previewScheduledPayment
- API key scope payments:read
- Tenant customer
Canonical RRULE and the next runs (nominal and execution dates, run instant). No writes.
API key scope: payments: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. |
Request body
scheduleobjectrequiredcurrencyCurrencyCoderequiredrailRaillimitinteger
Responses
200 OK
application/jsonrrulestringrequiredCanonical RRULE.
runsarray of PlannedRunrequired
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/scheduled-payments/preview" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Content-Type: application/json" \
--data '{
"schedule": {
"rrule": "string",
"startDate": "2026-09-30"
},
"currency": "GBP"
}'const response = await fetch("https://bank.wirebloom.com/v1/scheduled-payments/preview", {
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({
"schedule": {
"rrule": "string",
"startDate": "2026-09-30"
},
"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/scheduled-payments/preview",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Content-Type": "application/json",
},
json={
"schedule": {
"rrule": "string",
"startDate": "2026-09-30"
},
"currency": "GBP"
},
timeout=30,
)
response.raise_for_status()List internal transfers
GET /v1/transfers
- listTransfers
- API key scope payments:read
- Tenant customer
API key scope: payments: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. |
cursor | query | string | Opaque cursor from |
limit | query | integer | Page size (max 100). |
sort | query | string | Sort order; prefix |
filter | query | object | Filters as |
Responses
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+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/transfers" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/transfers", {
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/transfers",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()Internal transfer between own balances
POST /v1/transfers
- createTransfer
- API key scope payments:write
- Idempotency-Key required
- Tenant customer
Idempotency: Idempotency-Key is required. Replays within 24 h return the original response with Idempotency-Replayed: true.
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-Keyrequired | header | string | Unique key per logical operation (UUID v4 recommended). Scope: (credential principal, tenant, method, path). Retained 24 h. Same key + same body → original status and body replayed with |
Request body
fromBalanceIdUuidrequiredtoBalanceIdUuidrequiredamountPositiveMoneyrequiredreferencestring | null
Responses
201 Created
application/jsonInternal transfer between own balances of the same currency (payment
kind=internal, ledger-only).idUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
fromBalanceIdUuidrequiredtoBalanceIdUuidrequiredamountMoneyrequiredreferencestring | nullstatusPaymentStatusrequiredread-onlyFields of status
createdByUuidread-onlyFields of createdBy
createdAtTimestamprequiredread-onlyFields of createdAt
completedAtTimestamp | nulltransactionIdUuid | null
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/transfers" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
--data '{
"fromBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"toBalanceId": "0192a6f1-1111-7000-8000-00000000b002",
"amount": {
"amountMinor": "50000",
"currency": "GBP"
},
"reference": "Payroll top-up"
}'const response = await fetch("https://bank.wirebloom.com/v1/transfers", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.WIREBLOOM_API_KEY}`,
"X-Tenant-Id": process.env.WIREBLOOM_CUSTOMER_ID!,
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({
"fromBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"toBalanceId": "0192a6f1-1111-7000-8000-00000000b002",
"amount": {
"amountMinor": "50000",
"currency": "GBP"
},
"reference": "Payroll top-up"
}),
});
if (!response.ok) throw new Error(`${response.status} ${await response.text()}`);
const result = await response.json();import os, uuid
import requests
response = requests.request(
"POST",
"https://bank.wirebloom.com/v1/transfers",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json={
"fromBalanceId": "0192a6f1-1111-7000-8000-00000000b001",
"toBalanceId": "0192a6f1-1111-7000-8000-00000000b002",
"amount": {
"amountMinor": "50000",
"currency": "GBP"
},
"reference": "Payroll top-up"
},
timeout=30,
)
response.raise_for_status()Get transfer
GET /v1/transfers/{transferId}
- getTransfer
- API key scope payments:read
- Tenant customer
API key scope: payments:read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
transferIdrequired | path | Uuid | Identifier (transferId). |
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/jsonInternal transfer between own balances of the same currency (payment
kind=internal, ledger-only).idUuidrequiredread-onlyFields of id
customerIdUuidrequiredread-onlyFields of customerId
fromBalanceIdUuidrequiredtoBalanceIdUuidrequiredamountMoneyrequiredreferencestring | nullstatusPaymentStatusrequiredread-onlyFields of status
createdByUuidread-onlyFields of createdBy
createdAtTimestamprequiredread-onlyFields of createdAt
completedAtTimestamp | nulltransactionIdUuid | null
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+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/transfers/{transferId}" \
-H "Authorization: Bearer $WIREBLOOM_API_KEY" \
-H "X-Tenant-Id: $WIREBLOOM_CUSTOMER_ID"const response = await fetch("https://bank.wirebloom.com/v1/transfers/{transferId}", {
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/transfers/{transferId}",
headers={
"Authorization": f"Bearer {os.environ['WIREBLOOM_API_KEY']}",
"X-Tenant-Id": os.environ["WIREBLOOM_CUSTOMER_ID"],
},
timeout=30,
)
response.raise_for_status()