Versioning
All endpoints are prefixed with /v2. The version is part of the URL path, not a request header.
GET https://api.conduit.financial/v2/customers
All request bodies use JSON (Content-Type: application/json), except file uploads which use multipart/form-data.
All responses return JSON.
- Dates are ISO 8601 strings in UTC (e.g.,
2026-01-15T09:30:00.000Z).
- Nullable fields are explicitly
null in the response — they are never omitted.
- Empty collections are returned as
[], never null.
IDs
Resources use prefixed IDs (e.g., cus_abc123, app_xyz789). The prefix identifies the resource type:
| Prefix | Resource |
|---|
app | Application |
cus | Customer |
doc | Document |
org | Organization |
ord | Order |
txn | Transaction |
usr | User |
vac | Virtual account |
vrf | Verification |
wda | Webhook delivery attempt |
wdl | Webhook delivery |
wep | Webhook endpoint |
wlr | Whitelist recipient |
wlt | Wallet |
wsg | Wallet signer |
List endpoints use cursor-based pagination. Pass query parameters to control paging:
| Parameter | Default | Description |
|---|
cursor | (none) | Opaque cursor from a previous response. Omit for the first page. |
limit | 20 | Maximum results to return (1-100). |
direction | forward | forward or backward relative to the cursor. |
All list responses use the {data, meta} envelope shown above. meta.mode is "cursor" or "offset" depending on the endpoint.
{
"data": [...],
"meta": {
"mode": "cursor",
"nextCursor": "eyJpZCI6ImN1c18yeFBxTjhSIn0",
"previousCursor": null,
"total": 42
}
}
Use meta.nextCursor as the cursor parameter in the next request to fetch the next page. When nextCursor is null, there are no more results.
Cursors are opaque strings. Do not parse or construct them manually.
Errors
All error responses follow RFC 9457 (Problem Details for HTTP APIs):
{
"type": "VALIDATION_ERROR",
"title": "Validation Error",
"status": 400,
"detail": "The field 'email' is not a valid email address.",
"resolution": "Check the 'errors' array in the response for specific field-level issues and correct your request payload accordingly.",
"docs": "https://conduit-v2.mintlify.app/errors#validation-error",
"instance": "/v2/customers",
"correlationId": "corr_xyz789",
"timestamp": "2026-01-15T09:30:00.000Z"
}
| Field | Description |
|---|
type | Stable string code identifying the error. Use this for programmatic error handling. |
title | Human-readable summary. May change between versions. |
status | HTTP status code. |
detail | Specific explanation of what went wrong in this request. |
resolution | Suggested steps to fix the issue. |
docs | Link to the documentation page for this error code. |
instance | The resolved request URI for this occurrence (query string stripped). Include when contacting support. |
correlationId | Request correlation ID for tracing. |
timestamp | When the error occurred (ISO 8601 UTC). |
Always match on the type field for error handling, not status or title.
The type code is stable across API versions.
VALIDATION_ERROR (400), ONBOARDING_NOT_READY (422), and DOCUMENT_IDS_NOT_FOUND (400) include an errors array with one entry per offending field. Each entry has a pointer (JSON pointer to the invalid field), a detail (what is wrong, never echoes the rejected value), and an optional category (field, document, or individual) when the entry came from the requirements validator. category lets you group blockers without parsing pointers; it’s omitted on top-level schema rejections.
{
"type": "ONBOARDING_NOT_READY",
"title": "Onboarding Not Ready",
"status": 422,
"detail": "Validation failed",
"resolution": "Check the errors array for field-level details and fix the request body.",
"docs": "https://conduit-v2.mintlify.app/errors#onboarding-not-ready",
"instance": "/v2/onboarding",
"correlationId": "req_xyz",
"timestamp": "2026-04-27T20:00:00.000Z",
"errors": [
{ "pointer": "/businessInfo/taxId", "detail": "Tax ID is required", "category": "field" },
{ "pointer": "/documentIds", "detail": "At least one document is required", "category": "document" },
{ "pointer": "/ownership/persons", "detail": "At least 1 CONTROLLING_PERSON is required", "category": "individual" }
]
}
For a complete list of error codes, see the Error Codes Reference.
Idempotency
POST, PATCH, and PUT requests support idempotency via the idempotency-key header. Only successful responses are cached. Within a 5-minute window:
- Same key + same body after a success — returns the cached response instead of creating a duplicate resource. Replayed responses carry an
Idempotency-Replayed: true header.
- Same key + different body, after a success or a
5xx — rejected with 409 IDEMPOTENCY_KEY_CONFLICT. The key is bound to its first request body for the 5-minute window, so a modified payload never silently runs under another request’s key; send a genuinely new request with a fresh key.
- Retry after a
4xx — client errors commit nothing, so retrying with the same key is re-evaluated against current state, and a corrected body is accepted on the same key (fix a validation error and retry — no new key needed). On order execution, for example, a 422 INSUFFICIENT_FUNDS clears on retry once the balance covers the request. Payouts additionally bind the key to a terminally failed attempt — to retry a failed payout, use a fresh key.
curl -X POST https://api.conduit.financial/v2/onboarding \
-H "x-api-key: YOUR_API_KEY" \
-H "idempotency-key: unique-request-id" \
-H "Content-Type: application/json" \
-d '{ ... }'
Use a client-generated UUID or a deterministic key derived from the operation (e.g., onboard-{customer-external-id}).