API
Solicita acceso →
Empezar / Autenticación y firma

Autenticación y firma

Cada vez que le pides a Alibanca que mueva dinero, la API necesita estar segura de dos cosas: quién eres y que el mensaje llegó tal cual lo enviaste, sin que nadie lo tocara en el camino. Para eso, cada request lleva tu llave de API (te identifica) y una firma criptográfica RSA-SHA256 (prueba que el mensaje es auténtico e íntegro). Esta guía te explica, paso a paso y sin dar nada por sabido, cómo funcionan tus llaves, cómo se arma y se firma el envelope canónico, cómo el nonce evita que un request se reenvíe dos veces, y cómo depurar el temido error 401 cuando la firma no cuadra.

i
La idea en una frase. Tu llave dice "soy yo"; la firma dice "y este mensaje exacto salió de mí". Las dos juntas hacen que mover dinero sea seguro incluso sobre una red que no controlas.

Cómo funciona la autenticación en Alibanca

La autenticación de Alibanca tiene dos capas independientes que se refuerzan entre sí. Entenderlas por separado te ahorra horas de depuración, porque cuando algo falla casi siempre es una de las dos, no ambas.

Capa 1 — Identidad (tu llave de API). En cada request mandas el header x-api-key con tu llave secreta. Es como el nombre de usuario del request: le dice a Alibanca de qué cuenta viene la operación y qué permisos y límites aplican. Pero una llave, por sí sola, puede ser copiada; si alguien la ve, podría hacerse pasar por ti. Por eso existe la segunda capa.

Capa 2 — Autenticidad e integridad (la firma). Además de la llave, cada request lleva una firma digital en el header x-signature. Esa firma se calcula con una llave privada que solo tú tienes y que nunca viaja por la red. Alibanca la verifica con tu llave pública (que sí conoce). Si aunque sea un byte del mensaje cambió, o si quien lo firmó no tenía tu llave privada, la verificación falla y el request se rechaza. Esta capa es la que hace que mover dinero sea seguro: aun si alguien roba tu x-api-key, no puede firmar por ti sin tu privada.

i
Antes de firmar nada, saluda. Llama primero a GET /v2/version (es público, no requiere llave ni firma). Te confirma que estás apuntando al ambiente correcto y te devuelve los enlaces al openapi y al jwks. Es la forma barata de descartar problemas de red antes de meterte con la criptografía.

Tus llaves: sk_test_ y sk_live_

Una llave de API (API key) es un texto secreto que te identifica ante Alibanca. Tienes dos tipos, y la diferencia importa muchísimo porque una mueve dinero de verdad y la otra no.

PrefijoAmbienteQué hace
sk_test_SandboxVive en https://alibanca-api-production.up.railway.app. Corre contra un proveedor simulado (MockProvider): no mueve un solo céntimo real. Es tu campo de pruebas para desarrollar e integrar sin riesgo.
sk_live_ProducciónVive en https://api.alibanca.com. Cada request que aceptes aquí mueve dinero real. Trátala con el mismo cuidado que la clave de una bóveda.

El prefijo (sk_ = secret key) te recuerda que son secretas por diseño: no son un identificador público, son una credencial. En sandbox, además, tienes a tu disposición los montos mágicos → para disparar escenarios como unknown o el trap del doble-pago, y así probar que tu integración se comporta bien sin arriesgar dinero.

Pruébalo. Empieza siempre con sk_test_. Integra completo contra el sandbox, ejercita los montos mágicos, verifica tu manejo de unknown, y solo cuando todo el flujo esté sólido cambias la base URL y la llave a sk_live_. El código no cambia; solo el ambiente.

Seguridad de llaves: siempre del lado del servidor

Tu x-api-key y, sobre todo, tu llave privada RSA son secretos server-side. Eso significa que viven y se usan únicamente en tu backend — nunca en el navegador, nunca en una app móvil, nunca en código que el usuario final pueda descargar o inspeccionar.

La razón es simple: cualquier cosa que llegue al cliente, el cliente la puede leer. Si pones tu llave en el JavaScript de tu web o dentro de tu app, cualquiera con las herramientas de desarrollador puede extraerla y empezar a mover dinero como si fuera tú. La API de Alibanca siempre se llama desde tu servidor.

!
Nunca comitees una llave. No pongas sk_live_ ni tu llave privada en el repositorio, ni en un archivo .env que subas por accidente, ni pegada en un ticket, un chat o un PR. Guárdalas en un gestor de secretos o en variables de entorno del servidor. Si una llave se filtra, rótala de inmediato: asume que ya fue comprometida.

Buenas costumbres mínimas para dormir tranquilo:

1

Guárdalas fuera del código

Variables de entorno o un secret manager. Nunca hardcodeadas.

2

Sepáralas por ambiente

Que sk_test_ y sk_live_ vivan en configuraciones distintas, para que sea imposible mandar a producción algo que pensabas probar.

3

Protege la llave privada más que nada

Tu privada RSA es la joya de la corona. Con ella se firma el movimiento de dinero. Restringe quién y qué proceso puede leerla.

4

Rota ante la duda

Si sospechas exposición, rota. Es más barato rotar una llave sana que limpiar un fraude.

Firma asimétrica RSA-SHA256: qué es y por qué

Aquí está el corazón de la seguridad de Alibanca, así que vamos con calma y una analogía.

Firmar asimétricamente es como poner un sello de cera personal e infalsificable sobre un sobre cerrado. En criptografía asimétrica tienes dos llaves que forman una pareja: una privada (que solo tú tienes) y una pública (que puedes repartir sin miedo). Lo que se firma con la privada, solo se verifica con la pública correspondiente — y viceversa. Son matemáticamente inseparables, pero de la pública no se puede deducir la privada.

Aplicado a Alibanca: tú firmas cada request con tu llave privada, y Alibanca verifica esa firma con tu llave pública (que le registraste al dar de alta tu integración). El resultado tiene dos garantías:

Autenticidad — solo quien posee tu llave privada pudo producir esa firma, así que Alibanca sabe que el request salió realmente de ti, no de un impostor que copió tu x-api-key.

Integridad — la firma se calcula sobre el contenido exacto del mensaje. Si un intermediario cambia un solo carácter del monto o del destino, la firma deja de cuadrar y el request se rechaza. Nadie puede alterar un pago en tránsito sin que se note.

El SHA-256 de "RSA-SHA256" es la función de hash: antes de firmar, el mensaje se resume en una huella digital de tamaño fijo. Firmar esa huella con RSA es lo que produce la firma. No necesitas implementar esto a mano — cualquier librería de criptografía estándar (la nativa de tu lenguaje) lo hace por ti; solo tienes que darle el texto correcto a firmar. Y ese "texto correcto" es lo más importante de toda esta página: el envelope canónico.

El envelope canónico: qué se firma exactamente

No firmas "el request" en abstracto. Firmas un texto muy concreto y construido con reglas fijas, llamado envelope canónico. "Canónico" significa que se arma siempre igual, en un orden determinístico, para que tú y Alibanca lleguen exactamente al mismo texto y por tanto a la misma verificación. Si tú lo armas distinto a como Alibanca lo reconstruye, la firma no cuadra — aunque tu criptografía sea perfecta.

El envelope es la concatenación en este orden exacto de seis piezas:

OrdenPiezaQué es
1reqMétodo HTTPEl verbo del request, tal cual: POST, GET, PATCH, DELETE. En mayúsculas.
2reqRutaEl path del endpoint, por ejemplo /v2/payments. Es la ruta que estás llamando, sin el dominio.
3reqAPI keyTu x-api-key (sk_test_… o sk_live_…). Atarla al envelope amarra la firma a tu identidad.
4reqIdempotency-keyEl valor de tu header idempotency-key: el identificador único y determinístico de esta operación lógica.
5reqRaw bodyEl cuerpo crudo del request: el string JSON exacto, byte a byte, que vas a enviar. Ni re-serializado, ni con espacios distintos.
6reqNonceUn número creciente por llave que evita reenvíos (ver la sección del nonce). Viaja dentro del envelope firmado.
!
El detalle que rompe todo: el raw body. Debes firmar el mismísimo string que envías por la red, no un objeto que vuelves a serializar. Si firmas JSON.stringify(objeto) y luego tu cliente HTTP re-serializa el objeto con otro orden de claves u otros espacios, el body que llega a Alibanca ya no es el que firmaste, y obtienes 401. Regla de oro: serializa una sola vez, guarda ese string, fírmalo y envía ese mismo string.

Cómo armar y firmar el envelope

El proceso completo, del lado de tu servidor, en cuatro pasos:

1

Serializa el body una sola vez

Convierte tu objeto a JSON y guarda ese string. Ese es tu raw body — el que firmas y el que envías, sin volver a tocarlo.

2

Concatena las seis piezas en orden

Método, ruta, api-key, idempotency-key, raw body, nonce. En ese orden, con un separador consistente entre cada una.

3

Firma el envelope con tu llave privada

Aplica RSA-SHA256 sobre el envelope y codifica el resultado en base64. Esa es tu firma.

4

Manda los headers y el body

x-api-key, x-signature e idempotency-key en los headers; el raw body como cuerpo del request.

En pseudo-código (Node.js con la librería nativa crypto), se ve así:

NodeCopiar
// 0. Prepara los datos de la operación
const method  = "POST";
const path    = "/v2/payments";
const apiKey  = process.env.ALIBANCA_KEY;        // sk_live_...  (server-side)
const idemKey = "pay-2026-07-22-inv-8842";     // único y determinístico por operación
const nonce   = nextNonce(apiKey);              // creciente por llave (high-water)

// 1. Serializa el body UNA sola vez — este string es el que firmas Y envías
const rawBody = JSON.stringify({
  amountMinor: "150000",
  currency:    "VES",
  rail:        "PM",
  beneficiary: "0414-1234567"
});

// 2. Concatena las 6 piezas EN ORDEN (método, ruta, api-key, idem-key, body, nonce)
const envelope = [method, path, apiKey, idemKey, rawBody, nonce].join("\n");

// 3. Firma el envelope con TU llave privada → base64
const signature = crypto
  .createSign("RSA-SHA256")
  .update(envelope)
  .sign(privateKeyPem, "base64");

// 4. Envía. OJO: manda EXACTAMENTE rawBody como cuerpo, no re-serialices el objeto.
await fetch("https://api.alibanca.com/v2/payments", {
  method,
  headers: {
    "content-type":    "application/json",
    "x-api-key":       apiKey,
    "x-signature":     signature,
    "idempotency-key": idemKey
  },
  body: rawBody
});
i
El nonce viaja dentro del envelope. Fíjate que el nonce entra en la pieza 6 de lo que firmas, pero no es un header aparte: es parte del texto sellado. Al firmarlo, queda protegido por la misma firma, así que nadie puede cambiarlo sin invalidar todo el mensaje.

El nonce high-water: anti-replay para principiantes

Imagina que un atacante no logra romper tu firma, pero sí copia un request válido tuyo y lo reenvía tal cual, muchas veces. Como la firma es auténtica, ¿pasaría? A ese ataque se le llama replay (reenvío), y el nonce existe justo para bloquearlo.

Un nonce es un número que acompaña a cada request. Alibanca lleva, por cada llave, una marca de agua creciente (high-water mark): recuerda el nonce más alto que ya vio. La regla es simple: cada request nuevo debe usar un nonce mayor que el anterior. Cuando llega uno con un nonce igual o menor al que ya se registró, Alibanca sabe que es un reenvío o algo fuera de orden, y lo rechaza.

La analogía: es como el número de cheque de una chequera. Los cheques van 1001, 1002, 1003… Si al banco le llega otra vez el cheque 1002 después de haber procesado el 1003, sabe que es un duplicado y no lo paga. El nonce es ese número correlativo, pero por llave.

!
No confundas nonce con idempotency-key. Hacen cosas opuestas a propósito. El nonce impide que se reenvíe un request (siempre debe subir). La idempotency-key permite reintentar con seguridad una operación (se mantiene igual para devolverte el mismo resultado, no un pago nuevo). Reintentar bien = misma idempotency-key, nonce mayor.

Implementación práctica del lado tuyo: basta con que el nonce sea estrictamente creciente por llave. Un timestamp en milisegundos o microsegundos suele bastar; un contador persistente por llave también. Lo único inviolable es que nunca retroceda.

Los headers requeridos

Un request firmado a Alibanca lleva estos headers. Los tres primeros son la columna vertebral de la seguridad; el content-type es el estándar de cualquier request con cuerpo JSON.

HeaderTipoDescripción
x-api-keyreqstringTu llave de API (sk_test_… o sk_live_…). Te identifica y determina permisos y límites.
x-signaturereqstring (base64)La firma RSA-SHA256 del envelope canónico, hecha con tu llave privada. Prueba autenticidad e integridad.
idempotency-keyreqstringIdentificador único y determinístico de la operación lógica. Reintentar con el mismo valor devuelve el mismo resultado. Además forma parte del envelope firmado.
content-typestringapplication/json para requests con cuerpo. Estándar REST.
i
Endpoints públicos no piden nada de esto. GET /v2/version, GET /v2/openapi.json, GET /v2/webhook/keys (el JWKS) y GET /health son públicos: puedes llamarlos sin llave ni firma. Todo lo demás — mover dinero, listar pagos, gestionar beneficiarios, tu /v2/me — exige llave y firma.

Ejemplo de un request firmado completo

Así se ve, extremo a extremo, una emisión de pago firmada: primero el request con sus headers y su body, luego la respuesta.

HTTPCopiar
POST /v2/payments HTTP/1.1
Host: api.alibanca.com
content-type: application/json
x-api-key: sk_live_9f2c…a71b
x-signature: Qm9nT2xh… (RSA-SHA256 del envelope, en base64)
idempotency-key: pay-2026-07-22-inv-8842

{"amountMinor":"150000","currency":"VES","rail":"PM","beneficiary":"0414-1234567"}
RESPUESTA 201 application/json
{
  "status": "success",
  "traceId": "trc_7f3a91c0e2",
  "payload": {
    "id": "pay_01J8Z…",
    "state": "completed",
    "amountMinor": "150000",
    "currency": "VES"
  }
}

Fíjate en que el body de la respuesta sigue el sobre estándar de Alibanca: status, traceId (guárdalo: es tu número de referencia para soporte) y payload con el resultado. El campo state te dice cómo quedó el pago — profundiza en Estados de pago → para entender completed, unknown y failed.

Cómo Alibanca verifica tu firma

Entender qué hace Alibanca del otro lado te vuelve mucho más rápido depurando, porque sabes exactamente qué tiene que coincidir. Al recibir tu request, Alibanca:

1

Identifica tu llave

Lee x-api-key y busca la llave pública que registraste para esa cuenta.

2

Reconstruye el envelope

Vuelve a armar las seis piezas en el mismo orden — método, ruta, tu api-key, tu idempotency-key, el raw body que recibió y el nonce.

3

Verifica la firma

Comprueba, con tu llave pública, que la x-signature corresponde a ese envelope. Si un byte no cuadra, la verificación falla.

4

Chequea el nonce

Confirma que el nonce es mayor que la marca de agua de tu llave. Si es igual o menor, es replay y se rechaza.

Solo si las cuatro cosas pasan, Alibanca procesa la operación. Por eso la firma es una prueba tan fuerte: cualquier alteración del método, la ruta, la llave, la idempotency-key, el cuerpo o el nonce rompe la coincidencia.

Errores de firma (401) y cómo depurarlos

Cuando la autenticación falla, Alibanca responde con código 401 y el sobre de error { "error": "mensaje" }. Casi siempre la causa es que tu envelope no es idéntico al que Alibanca reconstruyó. Esta es tu lista de sospechosos, ordenada por frecuencia:

SíntomaCausa probableCómo arreglarlo
401 al azar en algunos requestsraw bodyEstás firmando un string pero enviando otro (tu cliente HTTP re-serializa el objeto). Serializa una vez, firma ese string y envía ese string.
401 constanteorden del envelopeLas piezas no están en el orden exacto método, ruta, api-key, idem-key, body, nonce. Revisa la concatenación.
401 constanteruta equivocadaFirmaste /payments en vez de /v2/payments, o incluiste el dominio, o un query string que no corresponde. Usa el path exacto.
401 tras rotar llavespar de llavesEstás firmando con una privada cuya pública no es la que Alibanca tiene registrada. Verifica que el par coincida (ver el fingerprint más abajo).
401 en reintentosnonceReusaste o bajaste el nonce. Cada request debe llevar un nonce estrictamente mayor.
401 con la llave correctaambienteMandaste una sk_test_ a producción o al revés. Verifica base URL y prefijo de llave.
i
Confirma qué llave está activa. Llama a GET /v2/me con tu llave firmada: te devuelve tu keyType, el environment y el publicKeyFingerprint (un SHA256:… de tu llave pública registrada). Si ese fingerprint no coincide con el de la pública que corresponde a tu privada, ahí está tu problema. /v2/me nunca devuelve secretos, así que es seguro para depurar.

Técnica de depuración recomendada. Cuando pelees con un 401, imprime en tu log el envelope exacto que estás firmando (con separadores visibles) y el body exacto que sale por la red. El 90% de los casos se resuelve al ver que esos dos strings no son los que creías. Compara carácter por carácter contra lo que esperas.

Buenas prácticas

Para cerrar, el resumen de hábitos que hacen tu integración segura y fácil de operar en el tiempo:

Serializa el body una sola vez. Es el error número uno. Guarda el string, fírmalo, envíalo. No dejes que ninguna capa lo re-serialice.

La privada nunca sale del servidor. Ni en logs, ni en el cliente, ni en el repo. Si dudas si se filtró, rota.

Nonce siempre creciente por llave. Un timestamp monotónico o un contador persistente. Que nunca retroceda, ni siquiera al reiniciar tu servicio.

Idempotency-key determinística por operación. Derívala de algo estable de tu lado (por ejemplo, el id de tu factura), no de un aleatorio nuevo en cada intento. Así un reintento de red reusa la misma clave y no genera un pago duplicado.

Saluda antes de firmar. GET /v2/version te confirma ambiente y conectividad sin criptografía de por medio; descarta problemas triviales antes de los complejos.

Separa ambientes con rigor. Config distinta para sk_test_ y sk_live_, base URLs distintas, y ojalá una salvaguarda que impida mandar test a producción.

Pruébalo. Antes de tocar sk_live_, monta todo el circuito de firma contra el sandbox: arma el envelope, fírmalo, emite un pago con un monto normal (queda completed) y luego con uno terminado en .02 para ver un unknown. Si tu firma cuadra en sandbox, cuadra en producción — la criptografía es idéntica; solo cambia que ahí el dinero es real.