Inicio rápido

Esta página va de una cuenta recién abierta a una Solicitud de Pago que un pagador puede pagar, en cuatro llamadas. Las cuatro van contra Sandbox, cuya base es https://api.sandbox.aloha.co/api/external, y cada una viene con el cuerpo que la API devuelve. Los campos, los tipos y los mensajes de esas respuestas son los que llegan de verdad; los identificadores, las fechas y los hosts que aparecen dentro son de ejemplo y se leen de la respuesta propia, no se copian de aquí. En Producción cambian el host y la clave; el contrato es el mismo.

La Clave API se crea en el panel, no desde la API

Ninguna de las dieciséis operaciones de la API emite una Clave API. La clave se crea en el panel del Ambiente donde se va a usar —el de Sandbox está en app.sandbox.aloha.co— desde la sección Claves API: se le da un nombre, se marcan los Permisos que va a llevar y, si hace falta, se restringen los Orígenes Permitidos. El Ambiente no se elige: el panel lo fija siempre en live, también en Sandbox. Crear una clave exige Verificar Identidad; no exige la Verificación Comercial, que en cambio sí hace falta para cobrar.

El secreto completo se devuelve una sola vez, en la respuesta que crea la clave. Ninguna petición posterior lo vuelve a entregar, así que se guarda en el mismo momento en que se lee. Una clave perdida no se recupera: se crea otra y se borra la anterior.

1. Las monedas de la cuenta confirman que la clave responde

GET /v1/wallets no exige ningún Permiso ni la cuenta verificada, así que es la llamada más barata para saber si la clave está bien puesta. Devuelve las monedas en las que la cuenta recibe el dinero: la mitad de destino de cada cobro.

curl https://api.sandbox.aloha.co/api/external/v1/wallets \
  -H "X-API-KEY: pay_aBcD1234_test_CLAVE_DE_EJEMPLO"
{
  "success": true,
  "message": "Wallets retrieved successfully",
  "data": [
    { "currency": "CLP" },
    { "currency": "USD" }
  ]
}

La lista no la ordena nada, así que se leen los valores de currency y no las posiciones. Es una proyección de en qué monedas acredita la cuenta, no un inventario de sus Billeteras: las monedas van sin repetir y las Billeteras en stablecoin no aparecen.

Lo que esta lista no es: la lista de monedas en las que se puede cobrar. Al crear una Solicitud de Pago, currency es la moneda del pagador, y sale de una lista fija de siete —ARS, BRL, COP, CLP, MXN, BOB y USD— que no depende de la cuenta. La moneda de destino no se nombra nunca: se deduce de currency. Por eso la cuenta de ejemplo acredita en CLP y en USD y la llamada siguiente cobra en COP sin contradecir nada — la moneda que paga el pagador y la que recibe la Billetera casi nunca son la misma.

2. Crear una Solicitud de Pago devuelve la dirección de checkout

Esta es la primera llamada con exigencias: el Permiso payment_links:create y la cuenta verificada, con Verificar Identidad y Verificación Comercial hechas las dos. Mientras falte cualquiera de ellas la respuesta es un 400 con code KYC_VERIFICATION_REQUIRED o KYB_VERIFICATION_REQUIRED, y no es un problema de la clave.

curl -X POST https://api.sandbox.aloha.co/api/external/v1/payment-links \
  -H "X-API-KEY: pay_aBcD1234_test_CLAVE_DE_EJEMPLO" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 150000,
    "currency": "COP",
    "description": "Reserva de hotel",
    "amount_type": "charge"
  }'
{
  "success": true,
  "message": "Payment link created successfully",
  "data": {
    "id": "9d8f7a6b-5c4d-3e2f-1a0b-9c8d7e6f5a4b",
    "url": "https://checkout.aloha.co/s/9d8f7a6b-5c4d-3e2f-1a0b-9c8d7e6f5a4b",
    "expires_at": null
  }
}

amount_type decide cuál de los dos montos queda fijo. Con charge, el del ejemplo, el pagador paga exactamente 150.000 COP y la cuenta se acredita lo que salga de la Tasa de Cambio; con receive, que es el valor por omisión, se fija en cambio lo que recibe la Billetera. Cuando las dos monedas coinciden —lo que ocurre siempre al cobrar en USD contra una Billetera en USD— no hay conversión que anclar: el campo no cambia ni lo que paga el pagador ni lo que se acredita en la Billetera.

Tres cosas de esta respuesta que conviene saber antes de guardarla:

  • url se entrega tal cual. Es la dirección que se le pasa al pagador, y es idéntica al checkout_url que devuelve la lectura. No se arma a mano a partir del id, y su host es el que publique el Ambiente que contestó: reenviarla sin modificarla es lo que la deja apuntando a donde tiene que apuntar.
  • expires_at viene null al crearla. Una Solicitud de Pago nace sin fecha de vencimiento, y mientras no la tenga nada la cierra con el tiempo: sigue siendo pagable hasta que se paga o se cancela. La gana después, si un pagador abre el checkout y elige un medio de pago: esa orden trae su propio plazo, que queda escrito en la Solicitud y es lo que devuelve la lectura. La que ya no deba poder pagarse se cancela.
  • El id es lo que hay que guardar para volver a la solicitud. Con él se lee y se cancela; ninguna operación de la API busca una Solicitud de Pago por otro campo.

Hay además un piso: una solicitud que convertida vale menos de 2.00 USD se rechaza con 400 y code BUSINESS_PAYMENT_LINK_MINIMUM_AMOUNT. Ese control corre antes que la validación del cuerpo, así que puede contestar antes de decir nada sobre los demás campos. Cuando se dispara, el monto que midió y la moneda en que lo midió vienen dentro de meta: un rechazo que parezca equivocado se lee ahí, no se adivina.

3. El Estado se lee de la Solicitud de Pago, no del pagador

curl https://api.sandbox.aloha.co/api/external/v1/payment-links/9d8f7a6b-5c4d-3e2f-1a0b-9c8d7e6f5a4b \
  -H "X-API-KEY: pay_aBcD1234_test_CLAVE_DE_EJEMPLO"
{
  "success": true,
  "message": "Payment link retrieved successfully",
  "data": {
    "amount": 150000,
    "currency": "COP",
    "currency_destiny": "CLP",
    "description": "Reserva de hotel",
    "expires_at": null,
    "max_uses": 1,
    "current_uses": 0,
    "status": "active",
    "checkout_url": "https://checkout.aloha.co/s/9d8f7a6b-5c4d-3e2f-1a0b-9c8d7e6f5a4b",
    "payment_method": null,
    "created_at": "2026-03-23T10:30:45.000000Z",
    "updated_at": "2026-03-23T10:30:45.000000Z"
  }
}

Doce campos, y el id no está entre ellos: se puso en la ruta y nada en el cuerpo lo repite. currency es la moneda del pagador y currency_destiny la de la Billetera que se acredita, que es la razón por la que casi nunca son la misma. status es el campo contra el que se decide entregar, y un Estado que no se reconozca se lee como «todavía sin resolver», nunca como un fallo.

Tres detalles que ahorran una sesión de depuración:

  • amount es el número que se declaró al crear —aquí, los 150.000 de la llamada anterior—, y el cuerpo no dice en cuál de las dos monedas está: amount_type no se devuelve, así que quien lea la solicitud sin saber cómo se creó no puede deducirlo de la respuesta. Con charge el monto está en currency; con receive, en currency_destiny. Tampoco es lo que acaba pagando el pagador cuando la Comisión se le suma por encima: para eso está el Pago Recibido, no este campo.
  • amount puede llegar como número JSON o como cadena numérica. Cuál de las dos no es algo que esta documentación prometa: conviene parsearlo como decimal desde cualquiera de las dos formas.
  • El id de la ruta tiene que ser un UUID bien formado. Cualquier otra cosa no llega a encajar con la ruta y vuelve como 404 con code RESOURCE_NOT_FOUND, antes incluso de que se mire la clave — así que una petición sin clave y con un id mal formado contesta 404 y no 401.

Esta lectura alcanza todas las Solicitudes de Pago del usuario dueño de la clave, incluidas las creadas desde el panel y las creadas con otras claves de ese mismo usuario. No alcanza las de otro usuario de la misma cuenta.

4. El secreto del webhook se muestra una sola vez

Consultar cada tanto sirve para probar. Para enterarse en el momento se registra un endpoint de webhook: una dirección propia a la que Aloha avisa cuando algo cambia. La url de abajo es un marcador y se sustituye por la del servidor propio, que tiene que ser alcanzable desde internet para que la entrega llegue.

curl -X POST https://api.sandbox.aloha.co/api/external/v1/webhooks \
  -H "X-API-KEY: pay_aBcD1234_test_CLAVE_DE_EJEMPLO" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/aloha",
    "description": "Endpoint de pruebas",
    "events": ["payment.completed", "payment_link.cancelled"]
  }'
{
  "success": true,
  "message": "Webhook endpoint created successfully",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "url": "https://example.com/webhooks/aloha",
    "description": "Endpoint de pruebas",
    "events": ["payment.completed", "payment_link.cancelled"],
    "secret": "4f3c2b1a09e8d7c6b5a4938271605f4e3d2c1b0a9f8e7d6c5b4a39281706f5e4",
    "is_active": true,
    "created_at": "2026-03-01T09:00:00+00:00"
  }
}

secret sale en esta respuesta y en la de rotación, y en ninguna otra operación de la API: son 64 caracteres hexadecimales en minúscula, sin prefijo y sin separador, y se guardan en el mismo momento en que se leen, porque ninguna petición posterior los devuelve. Con eso se firma cada entrega, y es lo que permite distinguir un aviso de Aloha de cualquier otra cosa que llegue a esa URL.

Lo demás de esta llamada:

  • El endpoint nace activo. is_active no se acepta al crearlo; para dejar de recibir entregas sin borrarlo se actualiza después.
  • Una URL se registra una vez por cuenta, no una por clave. Registrar una que ya esté registrada en la cuenta —la tenga la clave que la tenga, incluida esta misma— se rechaza con 422 y code WEBHOOK_ALREADY_EXISTS, y el rechazo no dice quién la tiene.
  • El endpoint sobrevive a la clave que lo creó. Borrar esa Clave API no borra el endpoint: queda registrado sin clave asociada, conserva su secret, sigue apareciendo en la lista y sigue recibiendo entregas. Para que deje de recibir hay que desactivarlo o borrarlo a él, que es otra operación. Cualquier clave de la cuenta con webhooks:write puede hacerlo, también una creada después.
  • Que un evento se acepte no garantiza que se entregue. La suscripción se escribe y la API contesta 201 igual, así que aceptar un evento no es por sí solo la prueba de que ese aviso va a llegar. Conviene comprobar en Sandbox cada evento sobre el que se vaya a apoyar lógica de negocio, en vez de darlo por vivo.

Seguir por aquí


Did this page help you?