Autenticación
API keys, su entorno (Sandbox o Live) y sus permisos, Sandbox y Live en los requests, el header Idempotency-Key, el formato de error, la paginación y los límites de requests.
Última actualización 27 oct 2026
La API vive en https://api.aliquot.cc. Todos los endpoints de vendedor están bajo /api/v1/crypto y se autentican con una API key. También la administración de webhooks, bajo /api/v1/organizations/{organizationId}/webhooks (ver Webhooks). Los endpoints para el comprador bajo /api/v1/public (checkout, páginas de payment links, reclamos de reembolso) no llevan autenticación: el ID de la factura, el slug del link o el token de reclamo en el path es la credencial.
Los requests y las respuestas son JSON, con nombres de campo en snake_case.
API keys
Creá las keys en el dashboard, en Desarrolladores → API keys. Dale un nombre a la key, elegí su entorno (Sandbox o Live, ver más abajo) y sus permisos y, si querés, una fecha de vencimiento. El secreto se muestra una sola vez, cuando se crea la key; Aliquot guarda solo un hash, así que un secreto perdido no se puede recuperar. En ese caso, creá una key nueva y revocá la anterior.
Una key pertenece a tu organización y actúa solo sobre sus datos. No podés darle a una key un permiso que tu propio rol en la organización no tiene.
Revocá una key desde la misma página. Una key revocada o vencida se rechaza de inmediato.
Keys y entornos
Cada key queda atada a un entorno, que elegís al crearla. Su prefijo dice cuál:
| Prefijo | Entorno | Acepta |
|---|---|---|
aq_sandbox_ | Sandbox | Solo mode: "test" y redes de prueba |
aq_live_ | Live | Solo mode: "live" y mainnets |
En el dashboard, el formulario de la key te pide el entorno (Sandbox por defecto). Por la API, mandá "environment": "sandbox" o "environment": "live" a POST /api/v1/organizations/{organizationId}/api-keys; por defecto es sandbox, o el entorno de la key que hace el request si es una key de Sandbox o de Live. Una key no puede crear una key del otro entorno: eso responde 403 API_KEY_ENVIRONMENT_MISMATCH.
Todo request bajo /api/v1/crypto hecho con la key se queda en su entorno:
- Si omitís el parámetro de query
mode, toma el entorno de la key: una key de Sandbox lista las facturas de Sandbox sin?mode=test. - Una factura creada sin
networknimodese crea en el entorno de la key. - Un
mode, unnetworko una red de losaccepted_pairsde un payment link del otro entorno responde403 API_KEY_ENVIRONMENT_MISMATCH, y no se crea nada. - Una factura, un payment link o un payout del otro entorno, leído, anulado o editado por ID, responde
404 NOT_FOUND, como si no existiera.
Los datos nunca cruzan de entorno: una factura de Sandbox nunca aparece en Live, y los saldos de Sandbox no se pueden pagar a una mainnet.
Keys legacy. Las keys creadas antes de que existieran los entornos empiezan con fk_live_ y no están atadas a ninguno: funcionan en los dos, y cada request elige su entorno como se explica en Sandbox y Live en los requests (los listados usan live por defecto). El dashboard las muestra como "Legacy · ambos entornos". Reemplazalas por una key de Sandbox o de Live.
Cómo mandar la key
Mandá el secreto como bearer token en el header Authorization:
curl "https://api.aliquot.cc/api/v1/crypto/invoices?mode=test" \
-H "Authorization: Bearer $ALIQUOT_API_KEY"Sin key, la respuesta es 401 UNAUTHORIZED. Una key inválida, revocada o vencida responde 401 UNAUTHORIZED con el mensaje Invalid or revoked API key. Una key válida sin el permiso que necesita un endpoint responde 403 FORBIDDEN con Missing permission: <permission>.
Los requests hechos con API keys quedan en el registro de requests: Desarrolladores → Registros en el dashboard, o GET /api/v1/crypto/requests. Cada entrada tiene el método, el path, el status, la duración, el Idempotency-Key si lo hubo, y si la respuesta fue un replay.
Permisos
| Endpoint | Permiso |
|---|---|
POST /api/v1/crypto/invoices | crypto-invoices:create |
GET /api/v1/crypto/invoices, GET /api/v1/crypto/invoices/{id} | crypto-invoices:read |
POST /api/v1/crypto/invoices/{id}/void | crypto-invoices:update |
POST /api/v1/crypto/quote | crypto-invoices:read |
GET /api/v1/crypto/networks | crypto-invoices:read |
GET /api/v1/crypto/refunds | crypto-invoices:read |
GET /api/v1/crypto/overview | crypto-invoices:read |
GET /api/v1/crypto/requests | crypto-invoices:read |
POST /api/v1/crypto/payment-links | crypto-links:create |
GET /api/v1/crypto/payment-links, GET /api/v1/crypto/payment-links/{id} | crypto-links:read |
PATCH /api/v1/crypto/payment-links/{id} | crypto-links:update |
POST /api/v1/crypto/accounts | crypto-accounts:create |
GET /api/v1/crypto/accounts, GET /api/v1/crypto/accounts/{id} | crypto-accounts:read |
GET /api/v1/crypto/balances, GET /api/v1/crypto/ledger/transactions, GET /api/v1/crypto/ledger/accounts | crypto-ledger:read |
POST /api/v1/crypto/payouts | crypto-payouts:create |
GET /api/v1/crypto/payouts, GET /api/v1/crypto/payouts/{id} | crypto-payouts:read |
/api/v1/organizations/{organizationId}/webhooks/… (endpoints, deliveries, resend) | webhooks:manage |
El formulario de keys del dashboard ofrece todos los permisos de esta tabla, agrupados por recurso y cada uno con una descripción de una línea. crypto-invoices:create, crypto-invoices:read, crypto-links:create, crypto-links:read, crypto-accounts:read y crypto-ledger:read vienen preseleccionados; crypto-invoices:update, crypto-links:update, crypto-accounts:create, crypto-payouts:read, crypto-payouts:create y webhooks:manage los marcás vos.
Keys que pueden hacer payouts
Una key con crypto-payouts:create saca dinero de tus saldos sin un código por cada payout. Por eso crearla exige una verificación adicional: necesitás tener la autenticación de dos factores activada en tu usuario (Configuración → Seguridad) y un código vigente de tu app de autenticación al momento de crear la key: en el dashboard, al marcar crypto-payouts:create aparece un campo para ingresarlo; por la API, mandalo como totp_code. Sin 2FA, el request responde 422 TWO_FACTOR_NOT_ENABLED; sin un código válido, 403 STEP_UP_REQUIRED. Una key que no se creó de esta forma responde 403 STEP_UP_REQUIRED en POST /api/v1/crypto/payouts. Ver Payouts.
Solo crypto-payouts:create hace que una key pueda hacer payouts. Los permisos se comparan de forma exacta, así que crypto-payouts:manage no incluye crypto-payouts:create ni crypto-payouts:read y no da acceso a ningún endpoint de payouts.
Sandbox y Live en los requests
Sandbox (mode: "test" en la API) y Live se separan por red, no por endpoint:
- Al crear una factura: el
networkque mandás decide el entorno (BASE_SEPOLIAes Sandbox,BASE_MAINNETes Live). Si dejás que el comprador elija la red, la factura toma el entorno de tu key; con una key legacy, mandá"mode": "test"o"mode": "live". Una red y unmodeque no coinciden dan422(con una key de Sandbox o de Live, el que no coincide con la key da403antes). - Los payment links toman su entorno de sus
accepted_pairs, y los payouts de sunetwork. - Al leer: los endpoints de listado aceptan un parámetro de query
mode, que por defecto es el entorno de tu key (livecon una key legacyfk_live_). Con una key legacy, agregámode=testpara ver facturas, payouts, reembolsos, payment links, saldos y asientos del ledger de Sandbox.
Toda factura, payout y payment link trae livemode: false en Sandbox, true en Live.
Idempotencia
POST /api/v1/crypto/invoices y POST /api/v1/crypto/payouts requieren un header Idempotency-Key (1–255 caracteres). Usá un valor que identifique la operación en tu sistema, como el ID de un pedido o de un retiro, y reusalo cuando reintentes.
| Situación | Respuesta |
|---|---|
| Sin header, o con más de 255 caracteres | 400 IDEMPOTENCY_KEY_REQUIRED |
| Primer request con la key | La respuesta normal (201) |
| Misma key, mismo request, el primero salió bien | La respuesta guardada, con status 200 y el header Idempotent-Replay: true |
| Misma key, distinto método, path o body | 409 IDEMPOTENCY_KEY_REUSED |
| Misma key mientras el primer request todavía se está procesando | 409 IDEMPOTENCY_IN_PROGRESS; reintentá en unos instantes |
Las keys tienen alcance de organización. Dos requests cuentan como el mismo cuando coinciden el método, el path y el body JSON; el orden de las claves dentro del body no importa. Solo se guardan las respuestas exitosas (2xx): si el primer request falla, la key se libera y podés corregir el request y mandarlo otra vez con la misma key.
Errores
Todos los errores tienen la misma forma:
{
"code": "VALIDATION_FAILED",
"message": "mode (test | live) is required when no network is given",
"issues": [{ "path": "mode", "message": "mode (test | live) is required when no network is given" }]
}code es estable y está pensado para tu código; message es para personas. issues aparece en los errores de validación y apunta al campo (path usa puntos para el anidamiento, como splits.0.percent).
| Status | code | Cuándo |
|---|---|---|
| 400 | BAD_REQUEST | El body no es JSON válido. |
| 400 | IDEMPOTENCY_KEY_REQUIRED | Falta Idempotency-Key en un endpoint que lo necesita. |
| 401 | UNAUTHORIZED | Sin key, o con una key inválida, revocada o vencida. |
| 403 | FORBIDDEN | A la key le falta el permiso, o la acción no está permitida. |
| 403 | STEP_UP_REQUIRED | La key no se autorizó para payouts cuando se creó. |
| 403 | API_KEY_ENVIRONMENT_MISMATCH | Una key de Sandbox usada para Live (un mode, una red o una key nueva de Live), o una key de Live usada para el Sandbox. Ver Keys y entornos. |
| 404 | NOT_FOUND | El objeto no existe en tu organización (o, con una key de Sandbox o de Live, es del otro entorno). |
| 409 | CONFLICT | El objeto está en un estado que no permite la acción (por ejemplo, anular una factura detectada), o una reference ya está tomada. |
| 409 | IDEMPOTENCY_KEY_REUSED, IDEMPOTENCY_IN_PROGRESS | Ver Idempotencia. |
| 409 | INSUFFICIENT_BALANCE | Un payout supera el saldo disponible. No se creó nada. |
| 413 | PAYLOAD_TOO_LARGE | El body pesa más de 1 MB. |
| 422 | VALIDATION_FAILED | Falta un campo o es inválido; ver issues. |
| 422 | TWO_FACTOR_NOT_ENABLED | Crear una key que puede hacer payouts sin 2FA. |
| 429 | RATE_LIMITED | Demasiados requests; ver más abajo. |
| 429 | STEP_UP_LOCKED | Demasiados códigos de dos factores fallidos; esperá 15 minutos. |
| 500 | INTERNAL_ERROR | Un error inesperado del lado de Aliquot. |
| 503 | CRYPTO_NOT_CONFIGURED | Los pagos no están disponibles en el servidor. |
Manejá los códigos que no reconozcas según su status HTTP.
Límites de requests
Los requests se cuentan por minuto, por separado para lecturas (GET) y escrituras (POST, PATCH, DELETE). Los valores por defecto son 300 lecturas y 60 escrituras por minuto. Los requests hechos con una API key cuentan para el usuario que creó la key; los endpoints públicos del checkout cuentan por dirección IP.
Las respuestas traen los headers estándar RateLimit y RateLimit-Policy con el límite, lo que queda y cuándo se reinicia la ventana. Por encima del límite, la API responde 429 con:
{ "code": "RATE_LIMITED", "message": "Too many requests. Try again later." }Paginación
GET sobre facturas, payouts, reembolsos, transacciones del ledger y el registro de requests devuelve una página:
{ "items": [], "next_cursor": "inv_01JB7Q8M3X4K9TPZ2R6WVN5HDC" }Mandá next_cursor de vuelta como cursor para obtener la página siguiente; vale null en la última página. limit va de 1 a 100 (25 por defecto; 50 para el registro de requests). Los items vienen del más nuevo al más viejo. Los demás endpoints de listado (redes, cuentas, payment links, saldos, cuentas del ledger) devuelven { "items": [...] } en una sola respuesta.
Montos e IDs
- Los montos son strings decimales, nunca números. Los precios en USD tienen como máximo dos decimales (
"100","100.5","100.00"); los montos en tokens son exactos, con al menos dos decimales ("102.50","76.875"). - Los porcentajes (
markup_percent,splits[].percent) son números JSON con como máximo dos decimales (2.5es 2.5 %). - Los IDs de objeto llevan un prefijo:
inv_facturas,acct_cuentas,po_payouts,rfd_reembolsos,plink_payment links,ltx_transacciones del ledger. Se ordenan por fecha de creación. - Los timestamps son ISO 8601 en UTC.