Alta de beneficiario, pendiente de aprobar en el panel
POST /v1/beneficiaries
Da de alta una cuenta destino. Nace pendiente y se aprueba en el panel, nunca por API: una llave robada no paga a un destino nuevo. Exige Idempotency-Key y firma. 201 si el alta quedó registrada; 202 si aún no se confirma: repite con la misma clave.
| Dato | Valor |
|---|---|
| Método y ruta | POST /v1/beneficiaries |
| Servidor | https://widget.fital.xyz |
operationId | createBeneficiary |
| Acceso | Llave con el scope beneficiaries:write |
| Firma de petición | Obligatoria en producción y en la cuenta de prueba. El simulador público no la valida. Ver Firma de petición |
| Idempotencia | Obligatoria, con Idempotency-Key. Ver Idempotencia |
raildecide qué campos se piden: cada variante del cuerpo tiene los suyos.- En
latam,entity,account_type,document_typeydocumentdependen del país:GET /v1/latam/countriesdice qué pide cada uno. Enpix,documentes opcional. - Si la misma cuenta ya estaba registrada, la respuesta trae el beneficiario que ya existe, con su
idy su estado. Guarda elidque recibes, no el que esperabas. 202significa que el alta aún no se confirma: elidya es válido yrail,countryycreated_atllegan ennull. Repite con la misma clave, o consulta elid.- El beneficiario nace
pending_approvaly se aprueba en el panel, nunca por API. En la cuenta de prueba naceapproved.
Encabezados de la petición
| Encabezado | Obligatorio | Descripción |
|---|---|---|
Authorization | Sí | Bearer y tu llave. |
Content-Type | Sí | application/json. |
Idempotency-Key | Sí | Clave única de esta operación, de 8 a 200 caracteres. Repetirla con el mismo cuerpo devuelve la misma respuesta durante 7 días. Con otro cuerpo da 422 idempotency_key_reused, también pasado ese plazo. |
X-Fital-Timestamp | Sí | Hora Unix en segundos. Se acepta hasta 300 s de diferencia. |
X-Fital-Signature | Sí | Firma v1= de la petición con el secreto de firma de la llave. |
X-Fital-Scenario | No | Sólo simuladores: elige la respuesta que quieres practicar. |
Cuerpo
Con rail: mxn_spei
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
clabe | texto | Sí | CLABE de 18 dígitos. |
holder_name | texto | Sí | Titular de la cuenta destino. Hasta 140 caracteres. |
rail | texto | Sí | Riel de pago. Decide qué campos se piden. mxn_spei: SPEI, en México. |
{
"rail": "mxn_spei",
"holder_name": "PROVEEDOR FICTICIO SA DE CV",
"clabe": "999180000000000011"
}Con rail: usd_ach
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
account_number | texto | Sí | Número de cuenta, de 4 a 17 dígitos. |
account_type | texto | Sí | Tipo de cuenta. checking: Cuenta de cheques o corriente. savings: Cuenta de ahorro. |
address | objeto | Sí | Domicilio del titular. |
address.city | texto | Sí | Ciudad. Hasta 100 caracteres. |
address.country | texto | Sí | País, en código de 3 letras. 3 caracteres. |
address.postal_code | texto | Sí | Código postal. Hasta 20 caracteres. |
address.state | texto | Sí | Estado o provincia. Hasta 100 caracteres. |
address.street_line_1 | texto | Sí | Calle y número. De 4 a 35 caracteres. |
holder_name | texto | Sí | Titular de la cuenta destino. Hasta 140 caracteres. |
rail | texto | Sí | Riel de pago. Decide qué campos se piden. usd_ach: ACH, en Estados Unidos. |
routing_number | texto | Sí | Número de ruta, 9 dígitos. |
{
"rail": "usd_ach",
"holder_name": "PROVEEDOR FICTICIO LLC",
"routing_number": "999999999",
"account_number": "000123456789",
"account_type": "checking",
"address": {
"street_line_1": "100 Calle Ficticia",
"city": "Ciudad Ficticia",
"state": "TX",
"postal_code": "00000",
"country": "USA"
}
}Con rail: usd_wire
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
account_number | texto | Sí | Número de cuenta, de 4 a 17 dígitos. |
account_type | texto | Sí | Tipo de cuenta. checking: Cuenta de cheques o corriente. savings: Cuenta de ahorro. |
address | objeto | Sí | Domicilio del titular. |
address.city | texto | Sí | Ciudad. Hasta 100 caracteres. |
address.country | texto | Sí | País, en código de 3 letras. 3 caracteres. |
address.postal_code | texto | Sí | Código postal. Hasta 20 caracteres. |
address.state | texto | Sí | Estado o provincia. Hasta 100 caracteres. |
address.street_line_1 | texto | Sí | Calle y número. De 4 a 35 caracteres. |
holder_name | texto | Sí | Titular de la cuenta destino. Hasta 140 caracteres. |
rail | texto | Sí | Riel de pago. Decide qué campos se piden. usd_wire: Wire, en Estados Unidos. |
routing_number | texto | Sí | Número de ruta, 9 dígitos. |
{
"rail": "usd_wire",
"holder_name": "PROVEEDOR FICTICIO LLC",
"routing_number": "999999999",
"account_number": "000123456789",
"account_type": "checking",
"address": {
"street_line_1": "100 Calle Ficticia",
"city": "Ciudad Ficticia",
"state": "TX",
"postal_code": "00000",
"country": "USA"
}
}Con rail: eur_sepa
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
bic | texto | Sí | Código BIC del banco. De 8 a 11 caracteres. |
holder_name | texto | Sí | Titular de la cuenta destino. Hasta 140 caracteres. |
iban | texto | Sí | IBAN de la cuenta. De 15 a 34 caracteres. |
iban_country | texto | Sí | País del IBAN, en código de 3 letras. 3 caracteres. |
rail | texto | Sí | Riel de pago. Decide qué campos se piden. eur_sepa: SEPA, en la zona euro. |
{
"rail": "eur_sepa",
"holder_name": "PROVEEDOR FICTICIO SL",
"iban": "XX00FICTICIO0000000000",
"bic": "FICTXXXX",
"iban_country": "ESP"
}Con rail: gbp_fps
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
account_number | texto | Sí | Número de cuenta, 8 dígitos. |
holder_name | texto | Sí | Titular de la cuenta destino. Hasta 140 caracteres. |
rail | texto | Sí | Riel de pago. Decide qué campos se piden. gbp_fps: Faster Payments, en Reino Unido. |
sort_code | texto | Sí | Sort code, 6 dígitos. |
{
"rail": "gbp_fps",
"holder_name": "PROVEEDOR FICTICIO LTD",
"account_number": "00000000",
"sort_code": "000000"
}Con rail: cop
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
bre_b_key | texto | Sí | Llave Bre-B del titular. Hasta 100 caracteres. |
holder_name | texto | Sí | Titular de la cuenta destino. Hasta 140 caracteres. |
rail | texto | Sí | Riel de pago. Decide qué campos se piden. cop: Bre-B, en Colombia. |
{
"rail": "cop",
"holder_name": "PROVEEDOR FICTICIO SAS",
"bre_b_key": "llave-bre-b-de-ejemplo"
}Con rail: pix
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
document | texto | No | Documento del titular. Hasta 20 caracteres. |
holder_name | texto | Sí | Titular de la cuenta destino. Hasta 140 caracteres. |
pix_key | texto | Sí | Llave PIX del titular. Hasta 100 caracteres. |
rail | texto | Sí | Riel de pago. Decide qué campos se piden. pix: PIX, en Brasil. |
{
"rail": "pix",
"holder_name": "PROVEEDOR FICTICIO LTDA",
"pix_key": "llave-pix-de-ejemplo",
"document": "00000000000"
}Con rail: latam
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
account_number | texto | Sí | Número de cuenta. GET /v1/latam/countries dice qué pide cada país. De 4 a 40 caracteres. |
account_type | texto | No | Tipo de cuenta, si el país lo pide. GET /v1/latam/countries dice qué pide cada país. checking: Cuenta de cheques o corriente. savings: Cuenta de ahorro. |
country | texto | Sí | País de la cuenta, en código de 2 letras. 2 caracteres. |
currency | texto | Sí | Moneda de la cuenta, en código de 3 letras. 3 caracteres. |
document | texto | No | Documento del titular, si el país lo pide. Hasta 30 caracteres. |
document_type | texto | No | Tipo de documento del titular, si el país lo pide. GET /v1/latam/countries dice qué pide cada país. Hasta 20 caracteres. |
entity | texto | No | Banco o entidad, si el país lo pide. Los valores salen de GET /v1/latam/countries/{country}/entities. Hasta 40 caracteres. |
holder_name | texto | Sí | Titular de la cuenta destino. Hasta 140 caracteres. |
rail | texto | Sí | Riel de pago. Decide qué campos se piden. latam: Transferencia local en otros países de América Latina. |
{
"rail": "latam",
"holder_name": "PROVEEDOR FICTICIO SPA",
"country": "CL",
"currency": "CLP",
"account_number": "00000000",
"entity": "000",
"document_type": "RUT",
"document": "00000000-0"
}Valores de rail
| Valor | Significado |
|---|---|
mxn_spei | SPEI, en México. Ver Pago SPEI. |
usd_ach | ACH, en Estados Unidos. Ver Pago ACH. |
usd_wire | Wire, en Estados Unidos. Ver Pago wire. |
eur_sepa | SEPA, en la zona euro. Ver Pago SEPA. |
gbp_fps | Faster Payments, en Reino Unido. Ver Pago FPS. |
cop | Bre-B, en Colombia. Ver Pago Bre-B. |
pix | PIX, en Brasil. Ver Pago PIX. |
latam | Transferencia local en otros países de América Latina. Ver Pago LatAm. |
Valores de account_type
| Valor | Significado |
|---|---|
checking | Cuenta de cheques o corriente. |
savings | Cuenta de ahorro. |
Respuestas correctas
201 Creado
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
country | texto o null | Sí | País de la cuenta, si se conoce. |
created_at | texto o null | Sí | Fecha de creación. ISO 8601 en UTC. |
id | texto | Sí | Identificador del beneficiario, con prefijo ben_. |
rail | texto o null | Sí | Riel del beneficiario. null mientras el alta no se confirme. mxn_spei: SPEI, en México. usd_ach: ACH, en Estados Unidos. usd_wire: Wire, en Estados Unidos. eur_sepa: SEPA, en la zona euro. gbp_fps: Faster Payments, en Reino Unido. cop: Bre-B, en Colombia. pix: PIX, en Brasil. latam: Transferencia local en otros países de América Latina. |
status | texto | Sí | Sólo con approved se le puede pagar. La aprobación se hace en el panel. processing: El alta sigue en curso. pending_approval: Falta aprobarlo en el panel. approved: Ya se le puede pagar. rejected: No se aprobó. deleted: Se dio de baja. |
Valores de rail
| Valor | Significado |
|---|---|
mxn_spei | SPEI, en México. |
usd_ach | ACH, en Estados Unidos. |
usd_wire | Wire, en Estados Unidos. |
eur_sepa | SEPA, en la zona euro. |
gbp_fps | Faster Payments, en Reino Unido. |
cop | Bre-B, en Colombia. |
pix | PIX, en Brasil. |
latam | Transferencia local en otros países de América Latina. |
null mientras el alta no se confirme.
Valores de status
| Valor | Significado |
|---|---|
processing | El alta sigue en curso. |
pending_approval | Falta aprobarlo en el panel. |
approved | Ya se le puede pagar. |
rejected | No se aprobó. |
deleted | Se dio de baja. |
{
"country": "MX",
"created_at": "2026-11-04T18:00:00.000Z",
"id": "ben_3kTMd9wQp2LxZ7vR1nYcA4bE",
"rail": "mxn_spei",
"status": "pending_approval"
}202 Aceptado: el resultado final llega después
Misma forma que la respuesta anterior.
{
"country": null,
"created_at": null,
"id": "ben_3kTMd9wQp2LxZ7vR1nYcA4bE",
"rail": null,
"status": "processing"
}Encabezados de la respuesta
| Encabezado | Contenido |
|---|---|
X-Request-Id | Identificador de la petición. Cítalo con soporte. |
Idempotent-Replayed | true si la respuesta repite una anterior con esa clave. |
Location | Ruta del recurso, con 201 y 202. |
Retry-After | Segundos a esperar, con 429, con 409 idempotency_in_progress y a veces con 503. |
Errores
Todos usan la forma de Errores: error.code, message, request_id, details, retryable y docs_url. Decide por code.
| HTTP | Código | Cuándo sale | retryable |
|---|---|---|---|
| 400 | invalid_request | Algún campo no cumple el esquema de su riel. En usd_ach y usd_wire, también si address.street_line_1 no trae número de calle. | false |
| 400 | idempotency_key_required | Falta Idempotency-Key. | false |
| 400 | idempotency_key_invalid | La clave no mide entre 8 y 200 caracteres, o viene duplicada. | false |
| 401 | invalid_api_key | La llave falta, está mal formada, venció o fue revocada, o la empresa está suspendida. | false |
| 401 | wrong_environment | La llave es de otro ambiente. | false |
| 401 | invalid_signature | Falta la firma, no coincide o tiene más de 5 minutos. | false |
| 403 | account_restricted | La cuenta tiene una restricción. | false |
| 403 | rail_not_enabled | El riel no está habilitado para tu empresa. En la cuenta de prueba, cualquier riel que no sea mxn_spei. | false |
| 403 | not_enabled | El riel latam no está activado para tu empresa. | false |
| 403 | forbidden_scope | La llave no tiene el scope de esta operación. details.required_scope lo nombra. | false |
| 403 | ip_not_allowed | La IP de origen no está activa en la lista de esa llave. | false |
| 403 | kyb_required | La empresa no tiene KYB aprobado o aún no está inscrita. | false |
| 403 | account_not_active | La cuenta no está activa. | false |
| 409 | beneficiary_ref_conflict | El identificador del alta ya existe. | false |
| 409 | idempotency_in_progress | Una petición anterior con esa clave sigue en curso. Llega con Retry-After. | true |
| 413 | invalid_request | El cuerpo supera 64 KB. | false |
| 422 | in_review | Una revisión de tu cuenta frena las altas nuevas. | true |
| 422 | invalid_beneficiary | El riel rechazó la cuenta destino por sus datos. En latam, también un número, banco, documento, moneda o tipo de cuenta que no cumple lo que pide el país: se responde al momento. | false |
| 422 | idempotency_key_reused | Usaste esa clave con otro cuerpo, también pasados 7 días. | false |
| 422 | sandbox_real_account_rejected (sólo cuenta de prueba) | La CLABE no empieza con 999 o el titular no incluye FICTICIO. | false |
| 422 | limit_exceeded (sólo cuenta de prueba) | Ya tienes 20 beneficiarios. | false |
| 429 | rate_limited | Superaste un límite de peticiones. Llega con Retry-After. | true |
| 500 | internal_error | Fallo nuestro. El resultado de la petición no se conoce. | true |
| 503 | service_unavailable | El servicio no está disponible por ahora. El resultado de la petición no se conoce. | true |
Ejemplos de error
400 invalid_request:
{
"error": {
"code": "invalid_request",
"message": "Petición inválida",
"request_id": "0123456789abcdef0123456789abcdef",
"details": {
"fields": {
"clabe": "Valor inválido"
}
},
"retryable": false,
"docs_url": "https://merchants.fital.xyz/docs/errores/#invalid_request"
}
}401 invalid_api_key:
{
"error": {
"code": "invalid_api_key",
"message": "Credencial inválida",
"request_id": "0123456789abcdef0123456789abcdef",
"details": {},
"retryable": false,
"docs_url": "https://merchants.fital.xyz/docs/errores/#invalid_api_key"
}
}403 account_restricted:
{
"error": {
"code": "account_restricted",
"message": "Tu cuenta tiene una restricción. Contacta a tu ejecutivo FITAL.",
"request_id": "0123456789abcdef0123456789abcdef",
"details": {},
"retryable": false,
"docs_url": "https://merchants.fital.xyz/docs/errores/#account_restricted"
}
}409 beneficiary_ref_conflict:
{
"error": {
"code": "beneficiary_ref_conflict",
"message": "Operación rechazada",
"request_id": "0123456789abcdef0123456789abcdef",
"details": {},
"retryable": false,
"docs_url": "https://merchants.fital.xyz/docs/errores/#beneficiary_ref_conflict"
}
}413 invalid_request:
{
"error": {
"code": "invalid_request",
"message": "Petición inválida",
"request_id": "0123456789abcdef0123456789abcdef",
"details": {},
"retryable": false,
"docs_url": "https://merchants.fital.xyz/docs/errores/#invalid_request"
}
}422 in_review:
{
"error": {
"code": "in_review",
"message": "La operación está en revisión",
"request_id": "0123456789abcdef0123456789abcdef",
"details": {},
"retryable": true,
"docs_url": "https://merchants.fital.xyz/docs/errores/#in_review"
}
}429 rate_limited:
{
"error": {
"code": "rate_limited",
"message": "Demasiadas peticiones",
"request_id": "0123456789abcdef0123456789abcdef",
"details": {},
"retryable": true,
"docs_url": "https://merchants.fital.xyz/docs/errores/#rate_limited"
}
}500 internal_error:
{
"error": {
"code": "internal_error",
"message": "Error interno",
"request_id": "0123456789abcdef0123456789abcdef",
"details": {},
"retryable": true,
"docs_url": "https://merchants.fital.xyz/docs/errores/#internal_error"
}
}503 service_unavailable:
{
"error": {
"code": "service_unavailable",
"message": "Servicio no disponible",
"request_id": "0123456789abcdef0123456789abcdef",
"details": {},
"retryable": true,
"docs_url": "https://merchants.fital.xyz/docs/errores/#service_unavailable"
}
}Reintentos
Ante un timeout o una conexión cortada, repite con la misma clave.
409 idempotency_in_progress: EsperaRetry-Aftery repite con la misma clave.422 in_review: Miraretryable. Contrue, repite con la misma clave cuando la revisión se levante. Confalse, el rechazo quedó registrado y esa clave lo repite: usa una clave nueva tras la revisión.429 rate_limited: Espera lo que indiqueRetry-Aftery repite.500 internal_error: Repite con espera exponencial.503 service_unavailable: Repite con espera exponencial. RespetaRetry-Aftersi viene.
Ver Reintentos y Límites.
Muestras
Variables de estas muestras: simulador público, sin cuenta
Define esto en tu terminal. Con estos valores las muestras corren tal cual contra el simulador público:
export FITAL_API="https://widget.fital.xyz/explorar/v1"
export FITAL_KEY="sk_test_sandbox_publica"
export FITAL_SIGNING_SECRET="secreto_de_firma_de_prueba_publico"En la cuenta de prueba o en producción cambia la base, la llave y el secreto, y sustituye los id de ejemplo por los tuyos. Ver Ambientes.
CUERPO='{"rail":"mxn_spei","holder_name":"PROVEEDOR FICTICIO SA DE CV","clabe":"999180000000000011"}'
CLAVE="ejemplo-crear-beneficiario"
TS=$(date +%s)
HASH=$(printf '%s' "$CUERPO" | openssl dgst -sha256 -r | cut -d' ' -f1)
FIRMA=$(printf '%s\n%s\n%s\n%s\n%s' "$TS" POST /v1/beneficiaries "$HASH" "$CLAVE" \
| openssl dgst -sha256 -hmac "$FITAL_SIGNING_SECRET" -r | cut -d' ' -f1)
curl -sS -X POST "$FITAL_API/beneficiaries" \
-H "Authorization: Bearer $FITAL_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $CLAVE" \
-H "X-Fital-Timestamp: $TS" \
-H "X-Fital-Signature: v1=$FIRMA" \
-d "$CUERPO"