Operating

API Error Codes

Structured API error responses, error codes, and HTTP status reference for Blnk Core 0.15.0 and later.

Blnk returns a stable error_detail.code on API errors. Use this code for programmatic handling.

Treat error, errors, and error_detail.message as display text only.

Error response shape

Error responses include error_detail and error (or errors on some list and filter endpoints):

{
  "error": "transaction not found",
  "error_detail": {
    "code": "TXN_NOT_FOUND",
    "message": "transaction not found",
    "details": {}
  }
}
FieldDescription
error_detail.codeStable code from the catalog below. Branch on this field, not on message text or error / errors.
error_detail.messageHuman-readable message. May change between releases.
error_detail.detailsOptional structured context (filter parse errors, reindex progress, batch IDs, and similar).
error or errorsExist for backwards compatibility and display.

How to handle errors

Handle Blnk API errors in two steps:

  1. Use the HTTP status code to understand the type of failure.
  2. Use error_detail.code to decide what your application should do.
const body = await response.json();

if (!response.ok) {
  const code = body.error_detail?.code;

  switch (code) {
    case "TXN_NOT_FOUND":
      // Show a not found state or retry with a valid transaction ID.
      break;
    case "TXN_DUPLICATE_REFERENCE":
      // Treat as a conflict. You may fetch the existing transaction by reference.
      break;
    case "TXN_INSUFFICIENT_FUNDS":
      // Ask the user to fund the source balance or choose another source.
      break;
    default:
      // Fall back to status-based handling.
      break;
  }
}

When debugging, log:

  • HTTP status code
  • error_detail.code
  • error_detail.details when present

These fields give you the clearest context without depending on message text.

Error-code catalog

Codes are domain-prefixed. Each code has one default HTTP status.

Platform

Errors that apply across endpoints: malformed requests, validation failures, rate limits, lock contention, and unexpected server failures. Codes use the GEN_* prefix.

CodeHTTPMeaning
GEN_MALFORMED_REQUEST400Request body could not be parsed (invalid JSON, wrong types, or body too large)
GEN_VALIDATION_ERROR400Request failed validation (invalid params, filters, fields)
GEN_MISSING_PARAMETER400A required route or query parameter is missing
GEN_BAD_REQUEST400Request rejected; no more specific code applies
GEN_NOT_FOUND404Resource not found; no domain-specific code applies
GEN_CONFLICT409Request conflicts with current resource state
GEN_RESOURCE_LOCKED423A concurrent operation holds the lock; retry shortly
GEN_PAYLOAD_TOO_LARGE413Reconciliation multipart upload exceeds the configured upload size. JSON bodies over the request size limit return 400 GEN_MALFORMED_REQUEST.
GEN_RATE_LIMITED429Too many requests
GEN_INTERNAL500Unexpected server failure; message is sanitized

Errors from API key authentication, authorization scopes, and metrics bearer tokens. Codes use the AUTH_* prefix.

CodeHTTPMeaning
AUTH_MISSING_API_KEY401No X-Blnk-Key header supplied
AUTH_INVALID_API_KEY401API key is unknown
AUTH_EXPIRED_API_KEY401API key is expired or revoked
AUTH_MISSING_PRINCIPAL401Authenticated API key principal missing from request context
AUTH_INSUFFICIENT_PERMISSIONS403API key lacks the required resource:action scope
AUTH_UNKNOWN_RESOURCE403Request path maps to no known resource
AUTH_MASTER_KEY_REQUIRED403Endpoint (hooks management) requires the master key
AUTH_CROSS_OWNER_ACCESS403Attempt to manage another owner’s API keys
AUTH_SCOPE_ESCALATION403Attempt to grant scopes broader than the caller’s
AUTH_METRICS_TOKEN_REQUIRED401/metrics requires Authorization: Bearer <token>
AUTH_INVALID_BEARER_TOKEN401/metrics bearer token mismatch
AUTH_METRICS_DISABLED403Secure mode on but no metrics bearer token configured

Errors when creating, listing, or validating API keys. Codes use the APIKEY_* prefix.

CodeHTTPMeaning
APIKEY_NOT_FOUND404API key does not exist
APIKEY_OWNER_REQUIRED400owner is required when creating or listing with the master key
APIKEY_INVALID400API key payload validation failure

Core resources

Errors when creating or fetching ledgers. Codes use the LGR_* prefix.

CodeHTTPMeaning
LGR_NOT_FOUND404Ledger does not exist
LGR_DUPLICATE409Ledger with this name or ID already exists

Errors when creating or fetching accounts. Codes use the ACC_* prefix.

CodeHTTPMeaning
ACC_NOT_FOUND404Account does not exist
ACC_DUPLICATE409Account already exists

Errors for balance lookups, historical snapshots, monitors, and validation. Codes use the BAL_* prefix.

CodeHTTPMeaning
BAL_NOT_FOUND404Balance does not exist, including a missing source or destination on a transaction route
BAL_HISTORY_NOT_FOUND404No balance snapshot or history at the requested time
BAL_INVALID_TIMESTAMP400Timestamp must be ISO 8601
BAL_VALIDATION_ERROR400Balance (or linked identity) validation failure
BAL_MONITOR_NOT_FOUND404Balance monitor does not exist

Errors when recording, validating, committing, voiding, or bulk-processing transactions. Codes use the TXN_* prefix.

CodeHTTPMeaning
TXN_NOT_FOUND404Transaction, refundable transaction, or queued source was not found
TXN_INSUFFICIENT_FUNDS400Source balance cannot cover the transaction
TXN_INVALID_AMOUNT400amount, precise_amount, or precision must not be negative
TXN_PRECISION_NOT_INTEGER400precision must be an integer value
TXN_INVALID_DISTRIBUTION400Multi-source or destination distribution is invalid
TXN_DUPLICATE_REFERENCE409The reference has already been used
TXN_NOT_INFLIGHT400Transaction is not in INFLIGHT status
TXN_ALREADY_COMMITTED409Inflight transaction was already committed
TXN_ALREADY_VOIDED409Inflight transaction was already voided
TXN_ALREADY_REFUNDED409Transaction was already refunded
TXN_COMMIT_AMOUNT_EXCEEDED400Commit exceeds the original or remaining inflight amount
TXN_INVALID_STATUS_ACTION400Inflight update status must be commit or void
TXN_BULK_EMPTY400Bulk payload contains no transactions or IDs
TXN_BULK_LIMIT_EXCEEDED400Bulk payload exceeds the per-request item limit
TXN_VALIDATION_ERROR400Transaction payload failed validation, including splitting sources and destinations at once

Errors for identity records and field tokenization. Codes use the IDT_* prefix.

CodeHTTPMeaning
IDT_NOT_FOUND404Identity does not exist
IDT_VALIDATION_ERROR400Identity payload validation failure
IDT_FIELD_NOT_TOKENIZABLE400Field is not in the tokenizable set
IDT_FIELD_ALREADY_TOKENIZED409Field is already tokenized
IDT_FIELD_NOT_TOKENIZED400Field is not tokenized and cannot be detokenized.
IDT_FIELD_NOT_FOUND400Field does not exist on the identity
IDT_TOKENIZATION_DISABLED403Tokenization is not configured on this server

Errors for reconciliation runs, matching rules, and external data uploads. Codes use the RECON_* prefix.

CodeHTTPMeaning
RECON_NOT_FOUND404Reconciliation run does not exist
RECON_RULE_NOT_FOUND404Matching rule does not exist
RECON_UPLOAD_FAILED400External data file upload failed because of the request.
RECON_UPLOAD_PROCESSING_FAILED500Server failed to process the uploaded file
RECON_UPLOAD_URL_INVALID400Upload URL is missing a host or is otherwise invalid
RECON_UPLOAD_HOST_NOT_ALLOWED400Upload URL host is not in the allowed list
RECON_RULE_INVALID400Matching rule failed validation. This can include name, criteria, operator, field, or drift errors.
RECON_MATCHING_RULES_REQUIRED400matching_rule_ids is required
RECON_EXTERNAL_TXNS_REQUIRED400external_transactions is required
RECON_START_FAILED500Reconciliation could not be started

Other operations

Errors when updating metadata on ledgers, balances, transactions, and other entities. Codes use the META_* prefix.

CodeHTTPMeaning
META_ENTITY_NOT_FOUND404Entity for metadata update does not exist
META_UNSUPPORTED_ENTITY400Entity type does not support metadata
META_INVALID_ENTITY_ID400Entity ID is missing or malformed

Errors for transaction hook registration and management. Codes use the HOOK_* prefix.

CodeHTTPMeaning
HOOK_NOT_FOUND404Hook does not exist
HOOK_INVALID400Hook payload validation failure
HOOK_OPERATION_FAILED500Hook registration, update, list, or delete infrastructure failure

Errors from queued async processing. Codes use the QUEUE_* prefix.

CodeHTTPMeaning
QUEUE_BACKPRESSURE503Enqueue rejected because Redis memory or pending task count exceeded configured limits

Errors from search queries and Typesense reindex jobs. Codes use the SRCH_* prefix.

CodeHTTPMeaning
SRCH_QUERY_INVALID400Search payload is invalid
SRCH_FAILED500Search backend failure
SRCH_REINDEX_IN_PROGRESS409A reindex is already running. details carries progress when available.
SRCH_REINDEX_NOT_STARTED404No reindex has been started

Errors from admin operations such as database backup. Codes use the ADMIN_* prefix.

CodeHTTPMeaning
ADMIN_BACKUP_FAILED500Database backup failed

Bulk commit and void

Bulk commit and void have two types of failures:

  1. Request-level failures
  2. Per-item failures

Request-level failures reject the whole request, i.e. they reject the whole call before any item runs. Per-item failures are returned inside the bulk result.

Request-level failures reject the whole request, i.e. they reject the whole call before any item runs. Per-item failures are returned inside the bulk result.

The response applies the standard transaction error shape with codes such as TXN_BULK_EMPTY or TXN_BULK_LIMIT_EXCEEDED.

{
  "error": "transactions cannot be empty",
  "error_detail": {
    "code": "TXN_BULK_EMPTY",
    "message": "transactions cannot be empty"
  }
}

Bulk commit expects a transactions array. Bulk void expects transaction_ids. Sending the wrong shape returns TXN_BULK_EMPTY because unrecognized fields are dropped.

Valid requests return HTTP 200 with succeeded, failed, and results. Branch on results[].code, not the HTTP status. Per-item codes are specific to bulk processing and are not part of the TXN_* catalog.

CodeMeaning
NOT_FOUNDTransaction ID does not exist
ALREADY_COMMITTEDInflight transaction was already committed
ALREADY_VOIDEDInflight transaction was already voided
NOT_INFLIGHTTransaction is not in INFLIGHT status
INVALID_AMOUNTCommit amount is invalid
LOCKEDConcurrent operation on the same transaction
INTERNAL_ERRORUnexpected server failure for this item
QUEUEDItem was queued for processing
ALREADY_QUEUEDA commit or void is already queued for this transaction
{
  "succeeded": 1,
  "failed": 2,
  "results": [
    {
      "transaction_id": "txn_f482a1b3-6c2d-4e89-a17b-3d5e8f2a1c94",
      "status": "succeeded"
    },
    {
      "transaction_id": "txn_c5d9e2a1-7b4f-4a3c-9e8d-1f6a2b4c8d30",
      "status": "failed",
      "code": "NOT_FOUND",
      "message": "Transaction with ID 'txn_c5d9e2a1-7b4f-4a3c-9e8d-1f6a2b4c8d30' not found"
    },
    {
      "transaction_id": "txn_7c91e4b2-3d8a-4f6e-b1c2-9a8d7e6f5b4a",
      "status": "failed",
      "code": "ALREADY_COMMITTED",
      "message": "Transaction is already committed"
    }
  ]
}

Loop through results and handle failed items by code. Queued items use status: "queued" and do not need the same error paths.

const { results } = await response.json();

for (const item of results) {
  if (item.status === "succeeded") {
    continue;
  }

  if (item.status === "queued") {
    // Item was queued for processing.
    // No error handling is needed unless your application treats queued items separately.
    continue;
  }

  if (item.status === "failed") {
    switch (item.code) {
      case "NOT_FOUND":
        // Confirm the transaction ID.
        break;
      case "ALREADY_COMMITTED":
      case "ALREADY_VOIDED":
        // Treat as already processed.
        break;
      case "LOCKED":
        // Retry shortly with backoff.
        break;
      default:
        // Handle NOT_INFLIGHT, INVALID_AMOUNT, INTERNAL_ERROR, and other failures.
        break;
    }
  }
}

Legacy codes

Blnk normalizes older generic error names to canonical error_detail.code values before the response leaves the server.

You will not receive legacy error names in error_detail.code. To handle legacy behaviour:

  • Use error_detail.code from the catalog above.
  • Prefer domain-specific codes over generic codes. For example, a missing transaction returns TXN_NOT_FOUND, not GEN_NOT_FOUND.
  • Do not parse error, errors, or error_detail.message to infer the code.
Legacy internal codeCanonical error_detail.code
NOT_FOUNDGEN_NOT_FOUND
CONFLICTGEN_CONFLICT
BAD_REQUESTGEN_BAD_REQUEST
INVALID_INPUTGEN_VALIDATION_ERROR
INTERNAL_SERVER_ERRORGEN_INTERNAL
RATE_LIMITEDGEN_RATE_LIMITED