https://api.veriko.mx/v1/validateValidate a SPEI transfer (direct)
How-to guide →Validates a SPEI transfer against the Banxico CEP from the fields sent:
- date
- amount
- tracking key
- numeric reference
- issuing bank
- receiving bank
- beneficiary account
The response is a verdict: valid, not_found, cep_unavailable, or error. This is the explicit route. The alternative, POST /v1/validate-ocr, takes the receipt image and infers those same fields from it; the verdict and the rest of the contract are identical. Asynchronous mode. With ?async=1 the operation is enqueued and the response is an immediate 202 carrying the identifier. The verdict is collected by polling GET /v1/validations/{id} until a terminal state; the cadence, and the use of ETag to avoid downloading the same thing twice, are covered in asynchronous operations. Every call consumes plan quota, in synchronous and asynchronous mode alike, and it is deducted when the request is accepted, not when it resolves. Exhausting the quota returns 429; how it is counted, and the caps, are covered in quotas and plans. Idempotency. The Idempotency-Key header is optional and prevents a duplicate validation when a network retry repeats the request. Reusing the key with a different body returns 422 idempotency_key_reused; doing so while the previous operation is still in flight returns 409 idempotency_key_in_progress. A 5xx response is not stored, so a server failure does not leave the key spent. A not_found, cep_unavailable, or error verdict is not necessarily final: the CEP can take time to publish. Automatic retries are enabled with PUT /v1/validations/{id}/retry-policy, or by sending retry_policy in this same body, and how they work is covered in the retry policy. The full history is available at GET /v1/validations.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
async | query | string | optional | When Default: |
Idempotency-Key | header | string | optional | Optional client-generated key (Stripe-style) that guarantees the request is processed exactly once within a 24-hour TTL. The scope is 11111111-2222-3333-4444-555555555555 |
| Parameter | Type | Required | Description |
|---|---|---|---|
fecha | string (date) (pattern, 10–10) | required | Transfer date in ISO 8601 format (YYYY-MM-DD). Must match the date registered in the CEP; differences of ±1 day may result in 2025-03-15 |
monto | number (double) (> 0) | required | Transfer amount in Mexican pesos (MXN), greater than zero and up to two decimal places. Must match exactly the amount registered in the CEP; any difference may result in 15000.5 |
clave_rastreo | string (1–30) | Required unless referencia_numerica is sent | SPEI tracking key generated by the sending bank: alphanumeric string of 18 to 30 characters. Required if MXBA20250315001234 |
referencia_numerica | string (pattern, 1–7) | Required unless clave_rastreo is sent | Numeric transfer reference: between 1 and 7 digits. Required if 1234567 |
emisor | string (?–255) | optional | Name of the sending bank. Free text; normalized internally against the Banxico catalog. Ignored for CLABE and card numbers, where the sender is derived from the account prefix. For phone/DiMo (10 digits), providing this field improves bank resolution. e.g.BANCO NACIONAL DE MEXICO |
receptor | string (?–255) | optional | Name of the receiving bank. For CLABE (18 digits) and card (16 digits) the bank is derived automatically from the prefix/BIN and this field is ignored. Only relevant when BBVA MEXICO |
cuenta_beneficiaria | string (pattern) | optional | SPEI destination account: 18-digit CLABE, 16-digit card number, or 10-digit DiMo phone number. The type is auto-detected by length and the appropriate checksum is validated (CLABE: standard check digit; card: Luhn). For phone numbers, the receiving bank is resolved from the user's whitelist then global catalog; if unresolvable, the validation result is 012180004412345678 |
retry_policy | object | optional | Automatic retry policy for this validation. If omitted, the policy configured at |
curl -X POST 'https://api.veriko.mx/v1/validate' \
-H 'Authorization: Bearer veriko_••••' \
-H 'Content-Type: application/json' \
-d '{
"fecha": "2025-03-15",
"monto": 15000.5,
"clave_rastreo": "MXBA20250315001234",
"referencia_numerica": "1234567",
"emisor": "BANCO NACIONAL DE MEXICO",
"receptor": "BBVA MEXICO",
"cuenta_beneficiaria": "012180004412345678"
}'Python example — coming soon.
JavaScript example — coming soon.
PHP example — coming soon.
| Field | Type | Description |
|---|---|---|
type* | string | JSON:API resource type. Always validation |
id* | string (uuid) | Unique identifier of the validation (UUID v4). e.g.3fa85f64-5717-4562-b3fc-2c963f66afa6 |
attributes* | object | Canonical validation data. |
validation_type | string |
direct |
is_playground | boolean | Whether the validation ran in playground mode. Playground executions still query Banxico but do not consume quota, emit webhooks, or fire notifications. e.g.false |
status | string | Lifecycle state: valid |
banxico_status | string | nullnullable | Banxico-reported status after query. valid |
processing_time_ms | integer | nullnullable | Milliseconds from enqueue to terminal resolution. e.g.1320 |
request_data | object | Literal snapshot of the original request fields. |
created_at | string (date-time) | UTC timestamp of enqueue. e.g.2025-03-15T14:22:10Z |
completed_at | string | nullnullable | UTC timestamp of terminal resolution. 2025-03-15T14:22:11Z |
enqueued_at | string | nullnullable | Timestamp of bus enqueue. e.g.2026-04-30T10:15:00Z |
processing_started_at | string | nullnullable | Timestamp of the first worker XCLAIM. e.g.2026-04-30T10:15:00Z |
expires_at | string | nullnullable | Expiration timestamp for queued validations. After this, the job moves to 2026-04-30T10:15:00Z |
etag_version | integer | nullnullable | Incremental version used for 1 |
image_path | string | nullnullable | Relative path of the receipt image. OCR only. e.g.ocr/2026/04/a1b2c3d4.jpg |
ocr_result | object | nullnullable | Raw OCR result. OCR only. |
ocr_confidence | number | nullnullable | OCR confidence 0–1. OCR only; 0.94 |
normalized_data | object | nullnullable | Normalized post-OCR fields used to query Banxico. |
normalization_warnings | array | nullnullable | Warnings emitted by the normalization pipeline. |
is_masked | boolean | nullnullable | Whether the receipt has a masked PAN. |
banxico_result | object | nullnullable | Literal payload returned by Banxico CEP. |
error_message | string | nullnullable | Human-readable error message when terminal. e.g.Banxico no respondió tras tres intentos. |
error_code | ValidationErrorCode | null | Machine-readable error code when terminal. |
batch_id | integer | nullnullable | Bulk import batch identifier if applicable. e.g.318 |
batch_position | integer | nullnullable | Position within the batch (1-indexed). e.g.12 |
retry_state | object | Full retry cycle state. Always present; if retries are not active, |
enabled | boolean | Whether the retry cycle is active for this validation. e.g.true |
max_retries | integer | nullnullable | Configured maximum number of retries. The upper bound depends on the plan ( 3 |
interval_seconds | integer | nullnullable | Interval between retries in seconds (300–86400). 600 |
outcomes | array | nullnullable | Validation outcomes that trigger a retry ( ["not_found","cep_unavailable","error"] |
attempts_completed | integer | Number of retries completed so far. e.g.1 |
next_attempt_at | TimestampUTC | null | Timestamp of the next scheduled retry. |
resolved_at | TimestampUTC | null | Timestamp when a retry resolved the validation to |
exhausted_at | TimestampUTC | null | Timestamp when retries were exhausted without resolution. |
cancelled_at | TimestampUTC | null | Timestamp when the cycle was explicitly cancelled. |
terminal_state | string | nullnullable | Terminal state of the cycle: pending |
links | object | Related links (JSON:API |
self | string | URL of the validation. e.g./v1/validations/3fa85f64-5717-4562-b3fc-2c963f66afa6 |
cep_xml | string | nullnullable | URL of the CEP in XML format. /v1/validations/a1b2c3d4-e5f6-7890-abcd-ef0123456789/cep.xml |
cep_pdf | string | nullnullable | URL of the CEP in PDF format. /v1/validations/a1b2c3d4-e5f6-7890-abcd-ef0123456789/cep.pdf |
| Status | Class | Description | Body |
|---|---|---|---|
| 200 | 2xx | Synchronous validation verdict. The status field takes one of: valid (transfer confirmed in the CEP), not_found (no record for the provided fields), cep_unavailable (Banxico did not respond in time), or error (unexpected pipeline failure). When has_cep: true the CEP certificate is available via GET /v1/validations/{id}/cep.
| No body |
| 202 | 2xx | Validation enqueued. Poll GET /v1/validations/{id} until one of the terminal statuses (valid, not_found, cep_unavailable, invalid, failed, error). meta.next_poll_after_seconds hints the recommended first-poll interval.
| ValidationQueued |
| 400 | 4xx | The Idempotency-Key header value does not meet the allowed format (alphanumeric + _ + -, 1–255 characters).
| ErrorResponse |
| 401 | 4xx | Authentication is required or the provided credentials are invalid. | ErrorResponse |
| 409 | 4xx | A request with the same Idempotency-Key is still being processed. The client must retry after the number of seconds indicated by the Retry-After header. In-flight rows older than idempotency.in_flight_timeout_seconds (300 by default) are automatically treated as zombies and cleaned up on the next attempt.
| ErrorResponse |
| 413 | 4xx | The request body exceeds the maximum accepted size (body_too_large). | ErrorResponse |
| 422 | 4xx | Request validation failed. Typical codes: clave_or_ref_required, required (fecha/monto), invalid_date, invalid_amount, invalid_account_format, invalid_account_length, invalid_clabe_checksum, invalid_card_luhn, retry_policy_invalid, retry_pending_cap_exceeded. Also emitted when an Idempotency-Key is reused with a different body (idempotency_key_reused). | ErrorResponse |
| 429 | 4xx | Rate limit exceeded | ErrorResponse |
| 503 | 5xx | Banxico upstream failure OR async dispatch failure (Redis down → dispatch_failed). Returns banxico_rate_limit_exhausted when Banxico is throttling and the platform exhausted its automatic retries. Wait a few minutes and retry. | ErrorResponse |
| Header | Type | Description |
|---|---|---|
Idempotent-Replayed | string | Only present when the client sent the Idempotency-Key header. false for fresh responses; true when the response is a replay from the idempotency cache (24h TTL keyed by user+endpoint+key). |
| Status | Code | Example |
|---|---|---|
| 400 | invalid_idempotency_key | Invalid Idempotency-Key format. Allowed: A-Z a-z 0-9 _ - (1-255 chars). Envelope
|
| 401 | unauthorized | Invalid or missing authentication credentials. Envelope
|
| 409 | idempotency_key_in_progress | A request with this Idempotency-Key is still being processed. Envelope
Response headers
|
| 413 | body_too_large | The request body is too large. Envelope
|
| 429 | rate_limit_exceeded | Rate limit exceeded. Try again in 45 seconds. Envelope
Response headers
|
Retry policy
POST /v1/validate
Automatic retry policy. Configures when and how many times the system retries a validation that returned an eligible outcome (not_found, cep_unavailable or error by default).
- Attempts
- —
- Interval
- 5 min – 1 h × 24
- Eligible outcomes
not_found,cep_unavailable,error
This operation accepts an optional retry policy.