Documentación

Construye conCryptocardium.

Emite tarjetas, financia cuentas, dispara transacciones y sigue el ciclo de vida — desde cURL, desde cualquier SDK, desde tu agente de IA. Toda la plataforma es una API REST estable y un servidor MCP nativo.

Bienvenida

Cryptocardium es un programa de tarjetas sin KYC financiado con cripto. Cada acción que puedes realizar en el panel — abrir una cuenta, recargar, emitir una tarjeta, cargarla, gastar, consultar transacciones — está disponible a través de la misma API REST y el mismo servidor MCP.

Estos docs cubren todo: convenciones (cómo habla la API), recursos (qué puedes pedir), eventos (cómo te mantienes sincronizado) e integraciones (Claude, ChatGPT, Cursor, cualquier agente).

Las claves API se generan en el panel.

Regístrate en /account, abre Configuración API, haz clic en "Nueva clave". El texto plano completo se muestra una sola vez — cópialo en un gestor de secretos.

Inicio rápido

De cero a una tarjeta virtual activa en tres llamadas. El shell de abajo usa cURL; sustitúyelo por cualquier cliente HTTP.

1. Autenticarse

Coloca tu clave API en la cabecera Authorization. Todos los endpoints la requieren.

export CCM_KEY="ccm_live_a1b2c3d4..."

2. Recargar la tesorería

Crea una dirección de depósito USDT. Envía fondos; acreditamos en la confirmación.

curl https://api.cryptocardium.com/v1/topups \
  -H "Authorization: Bearer $CCM_KEY" \
  -H "Idempotency-Key: top_$(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "amount_usd": 500, "asset": "USDT", "chain": "tron" }'

3. Emitir una tarjeta & gastar

Elige un BIN (Visa Platinum para carteras, Visa Business para publicidad), cárgalo y ya estás activo.

curl https://api.cryptocardium.com/v1/cards \
  -H "Authorization: Bearer $CCM_KEY" \
  -d '{
    "type": "virtual",
    "bin": "489517",
    "load_usd": 300,
    "wallet_provision": ["apple_pay", "google_pay"]
  }'

# → 201 Created · card is live, balance loaded, wallet-ready
Eso es todo.

Cuarenta y siete segundos de mediana, del registro a la primera autorización. Las secciones restantes cubren todo lo demás — gestión de errores, idempotencia, webhooks, configuración de agentes — que necesitarás en producción.

Autenticación

Tres tipos de credencial, elegidos según la forma de integración:

TipoFormatoUsar para
Bearer de sesiónsess_…Scripts interactivos, pruebas, el panel en sí.
Clave APIccm_live_…Servidores en producción, CI, tareas programadas, larga duración.
OAuth 2.1 + DCReyJh… (JWT)Agentes que se registran solos en tiempo de ejecución, permisos con alcance.

Cabecera bearer

Las tres pasan por la misma cabecera:

Authorization: Bearer ccm_live_a1b2c3d4...

Generar una clave API

Las claves se generan solo en el panel. No aceptamos solicitudes de creación de claves vía API sin una sesión autenticada vinculada a la sesión del panel.

  1. Inicia sesión en tu cuenta.
  2. Abre Configuración API.
  3. Haz clic en Nueva clave, dale un nombre reconocible, guarda el texto plano (se muestra una vez).
  4. Guárdalo en un gestor de secretos. Añádelo a tu entorno como CCM_KEY.
Trata las claves como contraseñas.

Una clave ccm_live_ filtrada tiene permisos a nivel de cuenta. Rótala en /api-settings si sospechas exposición — la revocación es instantánea.

Pruebas & sandbox

Actualmente, las recargas por debajo de 200 $ se aceptan como reales pero se enrutan a un procesador de tarjetas sandbox, por lo que puedes integrar sin consumir liquidación real. Las cuentas de producción tienen interruptores de modo sandbox por clave.

  • Recarga 200 $+ → raíles de producción, liquidación real.
  • Recarga <200 $ → raíles sandbox, autorizaciones simuladas.
  • Las tarjetas emitidas desde recargas sandbox llevan "mode": "sandbox".

URL base & versionado

URL base de producción:

https://api.cryptocardium.com/v1

El prefijo v1 forma parte de la ruta. v1 es LTS para siempre — nunca se publicarán cambios que rompan la compatibilidad bajo él. Los cambios aditivos (nuevos campos opcionales, nuevos endpoints) se publican de forma transparente.

Los cambios que rompen la compatibilidad van bajo un nuevo prefijo (v2) con al menos seis meses de solapamiento. Las deprecaciones se anuncian vía webhook (system.deprecation) y el registro de cambios.

Solicitudes

Todas las solicitudes son HTTPS únicamente (TLS 1.3). Los cuerpos de solicitud son JSON; los objetos anidados son de primer nivel. Los cuerpos codificados en formulario no están soportados.

  • Content-Type: application/json para endpoints de escritura.
  • <strong>Charset</strong>: UTF-8 siempre.
  • Métodos HTTP: GET (leer), POST (crear / acción), PATCH (actualización parcial), DELETE (eliminar).
  • Límites de cabecera: 8 KB total, 4 KB por valor.
  • Límite de cuerpo: 25 MB (100 MB para cargas de evidencias de disputa).
  • Timeouts: 30 s de conexión, 60 s de lectura. Las operaciones de larga duración son asíncronas.

Respuestas

Cada respuesta es JSON. Las respuestas exitosas devuelven 200/201/204 con el cuerpo del recurso. Los errores devuelven un objeto de error estructurado — ver Errores.

Envelope estándar

{
  "id": "card_8f3a91b7c4d2",
  "object": "card",
  "created_at": "2026-05-19T07:30:00Z",
  "updated_at": "2026-05-19T07:30:00Z",
  ...
}

Marcas de tiempo

Todas las marcas de tiempo son ISO 8601 en UTC, formateadas como YYYY-MM-DDTHH:MM:SSZ. No hay otras zonas horarias en la API.

Valores monetarios

Todos los importes son decimales equivalentes a USD en campos amount_usd. Precisión de dos decimales. Respaldado internamente por USDT.

Paginación

Los endpoints de lista (/topups, /cards, /transactions, …) están paginados por cursor. Sin offset, sin LIMIT SQL.

GET /v1/transactions?limit=50&cursor=tx_8f3a91b7c4d2
  • limit — tamaño de página, por defecto 25, máximo 100.
  • cursor — devuelve el next_cursor de la respuesta anterior.
  • La paginación sigue el orden natural de cada recurso (normalmente <code>created_at</code> desc).
{
  "object": "list",
  "data": [ /* 50 items */ ],
  "has_more": true,
  "next_cursor": "tx_2bea88..."
}

Filtrado & ordenación

Cada endpoint de lista admite filtrado en sus campos principales mediante parámetros de consulta:

GET /v1/transactions
  ?card_id=card_8f3a91b7c4d2
  &status=captured
  &created_after=2026-05-01T00:00:00Z
  &sort=-amount_usd

El parámetro sort acepta un solo campo; usa el prefijo - para descendente. Consulta la referencia de endpoint de cada recurso para conocer las claves de filtro admitidas.

Idempotencia

Cada solicitud de escritura (POST, PATCH, DELETE) acepta una cabecera Idempotency-Key. Pasa un valor único por operación lógica. Los reintentos con la misma clave devuelven la respuesta original.

POST /v1/cards
Idempotency-Key: card_create_b9f1a4...
Authorization: Bearer ccm_live_...
  • Las claves se almacenan durante 24 horas. Después, la misma clave puede reutilizarse para una operación nueva.
  • Formato recomendado: <operación>_<uuid-v4>.
  • Misma clave + cuerpo diferente → 409 Conflict con conflict_idempotency_key.
  • Las solicitudes GET son siempre idempotentes y no necesitan (ni aceptan) la cabecera.

Límites de tasa

Por clave API:

VentanaLímiteNotas
Ráfaga de 1 s60 reqSe toleran picos cortos.
1 min1 000 reqTecho sostenido.
1 día50 000 reqAgregado por clave.

Cada respuesta incluye:

X-RateLimit-Limit:     1000
X-RateLimit-Remaining: 943
X-RateLimit-Reset:     1718999999

Cuando superas el límite, recibirás 429 Too Many Requests con una cabecera Retry-After en segundos. Respétala; aplicamos backoff exponencial a los infractores.

Errores

Cada respuesta de error usa la misma forma:

{
  "object": "error",
  "type": "invalid_request_error",
  "code": "missing_required_field",
  "message": "Field 'bin' is required.",
  "param": "bin",
  "request_id": "req_a9f4b1..."
}

Mapeo de estado HTTP

EstadoTipoSignificado
400invalid_request_errorPayload malformado, campos que faltan.
401authentication_errorBearer ausente o inválido.
403permission_errorBearer válido, acción no permitida (p. ej., restricción de saldo).
404not_found_errorEl recurso no existe (o no es tuyo).
409conflict_errorConflicto de estado (p. ej., clave de idempotencia reutilizada).
419session_expiredSesión del panel expirada. Reautentícate.
422validation_errorJSON válido, regla de negocio incumplida.
429rate_limit_errorReduce la velocidad. Retry-After en segundos.
500api_errorNuestro error. Ya hemos sido alertados.
503service_unavailableEmisor upstream caído. Se recomienda reintento automático.

Registra siempre el request_id. Los tickets de soporte lo referencian directamente.

Cuentas

La cuenta es tu recurso raíz. Todo lo demás (recargas, tarjetas, transacciones) pertenece a una cuenta.

Crear

POST /v1/accounts
{
  "email": "[email protected]",
  "password": "long-random-string"
}

Devuelve un bearer de sesión de inmediato. Sin KYC, sin subir documentos, sin paso de verificación de email necesario para empezar a usar la API.

Recuperar la actual

GET /v1/accounts/me
{
  "id": "acc_8f3a91b7c4d2",
  "email": "[email protected]",
  "balance_usd": 487.20,
  "twofa_enabled": true,
  "created_at": "2026-05-18T20:14:00Z"
}

Saldo & tesorería

El saldo de la cuenta es el fondo USDT disponible para gastar. Las recargas lo incrementan; las cargas de tarjeta y las retiradas lo decrementan.

GET /v1/balance
{
  "object": "balance",
  "available_usd": 487.20,
  "pending_usd": 200.00,
  "updated_at": "2026-05-19T07:30:00Z"
}

pending_usd cubre recargas en vuelo (aún no confirmadas) y cargas de tarjeta en vuelo.

Recargas

Una recarga es el paso asimétrico donde comprometes cripto en cadena y nosotros acreditamos USDT tras la finalidad.

Crear

POST /v1/topups
{
  "amount_usd": 500,
  "asset": "USDT",
  "chain": "tron"
}

Devuelve una dirección de depósito, datos URI de QR y una expiración (por defecto 60 min). Envía el importe exacto a la dirección; acreditamos en la confirmación.

{
  "id": "top_4e21a99c7b",
  "status": "pending",
  "amount_usd": 500,
  "deposit_address": "T9zFR...kQp",
  "qr_data_uri": "data:image/png;base64,...",
  "expires_at": "2026-05-19T08:30:00Z"
}

Ciclo de vida del estado

EstadoSignificado
pendingEsperando depósito en cadena.
completedFondos acreditados al saldo.
expiredVentana de dirección cerrada. Los depósitos tardíos se acreditan automáticamente.
cancelledLlamaste a POST /v1/topups/:id/cancel.
errorLiquidación fallida (infrecuente). Reembolsado automáticamente.

Usa el webhook topup.confirmed en lugar de sondear — se dispara una vez y te ahorra más de 30 sondeos.

Tarjetas

Las tarjetas son de dos tipos: virtual (activa en segundos) y física (enviada en 5–9 días, limitada al BIN de Visa Gold).

Emitir

POST /v1/cards
{
  "type": "virtual",
  "bin": "489517",
  "load_usd": 300,
  "wallet_provision": ["apple_pay", "google_pay"]
}

Catálogo de BIN

BINNombreIdeal paraTipo
416842Visa BusinessGasto publicitario (3-D Secure)Virtual
557213Mastercard WorldMultidivisa, premiumVirtual
489517Visa PlatinumApple & Google PayVirtual
472305Visa CorporateSuscripciones SaaSVirtual
448585Visa GoldSolo física (3-D Secure)Física

Revelar PAN completo + CVV

El número completo de tarjeta, CVV y vencimiento se devuelven solo en una llamada dedicada y auditada:

GET /v1/cards/:id/pan
{
  "pan": "4895 1712 ●●●● 4218",
  "cvv": "347",
  "expires_at": "2029-08",
  "audit_id": "audit_8c2e3f..."
}

Cada revelación queda registrada en el rastro de auditoría. Los agentes deben revelar una vez por compra, nunca almacenar y descartar de la memoria tras el uso.

Operaciones

  • POST /v1/cards/:id/freeze — detener autorizaciones.
  • POST /v1/cards/:id/unfreeze — reanudar.
  • POST /v1/cards/:id/load — añadir USDT a la tarjeta.
  • POST /v1/cards/:id/unload — mover el saldo no utilizado de vuelta a la tesorería.
  • POST /v1/cards/:id/cancel — cancelación permanente.
  • PATCH /v1/cards/:id/limits — límites de transacción / mensuales por tarjeta.
  • PATCH /v1/cards/:id/mcc — listas de MCC permitidos/denegados.
  • PATCH /v1/cards/:id/geo — listas de países permitidos.

Cargas & saldos de tarjeta

El saldo de tarjeta está denominado en USDT equivalente a USD. Una carga deduce de la tesorería, aplica la comisión de rail del 2 % y acredita la tarjeta.

POST /v1/cards/:id/load
{ "amount_usd": 200 }
{
  "card_id": "card_8f3a91b7c4d2",
  "loaded_usd": 200.00,
  "rail_fee_usd": 4.00,
  "new_card_balance_usd": 200.00,
  "new_treasury_balance_usd": 283.20
}

Las cargas son atómicas — la llamada devuelve respuesta solo tras el movimiento de fondos.

Transacciones

Cada autorización, captura, reembolso y rechazo es un objeto de transacción. Son de solo adición e inmutables.

GET /v1/cards/:id/transactions?status=captured&limit=50
{
  "object": "list",
  "data": [
    {
      "id": "tx_b1c2d3",
      "object": "transaction",
      "card_id": "card_8f3a91b7c4d2",
      "status": "captured",
      "amount_usd": 42.95,
      "merchant": { "name": "OpenAI", "mcc": "7372" },
      "auth_response_code": "00",
      "created_at": "2026-05-19T03:14:00Z"
    }
  ],
  "has_more": false
}

Filtra por status, card_id, mcc, merchant_name, created_after, created_before, amount_min, amount_max.

Retiradas

Envía USDT de la tesorería a cualquier cartera externa que controles.

POST /v1/withdrawals
{
  "amount_usd": 100,
  "chain": "tron",
  "address": "T9zFR...kQp"
}

Mín. 10 $, máx. tu saldo completo. Cadenas soportadas: tron (la más barata), ethereum, bsc. Los envíos entre redes son irrecuperables — verifica siempre la dirección.

Disputas

Presenta un contracargo sobre cualquier transacción:

POST /v1/disputes
{
  "transaction_id": "tx_b1c2d3",
  "reason": "duplicate",
  "description": "Merchant charged twice on 2026-05-19, same order #4921."
}

Códigos de motivo: duplicate, not_received, fraud, not_as_described, cancelled_subscription, other.

Adjunta evidencias (recibos, capturas, correspondencia) vía POST /v1/disputes/:id/evidence. Tramitamos ante el emisor en tu nombre — sin coste adicional.

Webhooks · suscribirse

Los webhooks envían eventos a tu endpoint HTTPS a medida que ocurren. Evita el sondeo; usa webhooks.

POST /v1/webhooks
{
  "url": "https://yourapp.example.com/webhooks/cryptocardium",
  "events": [
    "topup.confirmed",
    "card.issued",
    "transaction.captured",
    "transaction.declined"
  ],
  "description": "Production sync"
}

La respuesta contiene un signing_secret — guárdalo; lo necesitarás para verificar los payloads. Suscríbete a "*" para recibir cada evento.

Webhooks · verificación de firma

Cada webhook lleva una firma HMAC-SHA256 en la cabecera Cryptocardium-Signature:

Cryptocardium-Signature: t=1718999999,v1=4a8b2f0e6c9d...
Cryptocardium-Event-Id:  evt_a1b2c3d4
Cryptocardium-Delivery:  dlv_8f3a91...

Calcula la firma esperada sobre "{t}.{rawBody}" con tu signing_secret. Compara usando una función de tiempo constante.

Node.js

import crypto from 'crypto';

export function verify(rawBody, sigHeader, secret) {
  const [t, v1] = sigHeader.split(',')
    .map(s => s.split('=')[1]);
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${t}.${rawBody}`)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(v1), Buffer.from(expected)
  );
}

Python

import hmac, hashlib

def verify(raw_body: bytes, sig_header: str, secret: str) -> bool:
    parts = dict(p.split('=') for p in sig_header.split(','))
    t, v1 = parts['t'], parts['v1']
    expected = hmac.new(
        secret.encode(),
        f"{t}.{raw_body.decode()}".encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(v1, expected)

PHP

function verify($rawBody, $sigHeader, $secret): bool {
    $parts = [];
    foreach (explode(',', $sigHeader) as $p) {
        [$k, $v] = explode('=', $p, 2);
        $parts[$k] = $v;
    }
    $expected = hash_hmac('sha256',
        "{$parts['t']}.{$rawBody}", $secret);
    return hash_equals($expected, $parts['v1']);
}

Webhooks · reintentos & reproducciones

Entrega al menos una vez. Reintentamos en cualquier respuesta no-2xx o timeout (10 s).

IntentoRetraso
1inmediato
230 s
35 min
430 min
52 h
612 h
724 h (final)

Reproduce cualquier evento desde el panel o vía POST /v1/webhooks/:id/replay/:event_id. Usa la cabecera Cryptocardium-Event-Id para deduplicación en tu lado.

Catálogo de eventos

Account account.created account.signed_in account.signed_out account.password_changed account.totp_enabled account.totp_disabled
Top-ups topup.created topup.confirmed topup.expired topup.cancelled topup.error
Cards card.issued card.loaded card.unloaded card.frozen card.unfrozen card.cancelled card.replaced
Tx transaction.authorized transaction.captured transaction.refunded transaction.declined transaction.reversed
Dispute dispute.opened dispute.responded dispute.won dispute.lost
Withdraw withdrawal.created withdrawal.broadcasted withdrawal.confirmed withdrawal.failed
System system.maintenance system.deprecation

Servidor MCP

Alojamos un servidor del Protocolo de Contexto de Modelo en https://mcp.cryptocardium.com/v1. Expone más de 40 herramientas mapeadas 1:1 a endpoints REST, con nombres adaptados para agentes (create_topup, issue_card, reveal_pan, etc.).

Transporte: HTTP streamable. Auth: OAuth 2.1 con Registro Dinámico de Clientes — los agentes se registran solos en la primera conexión, sin necesidad de pegar una clave API en la configuración del agente.

MCP · configuración del cliente

Claude Desktop / Claude Code

// ~/.config/claude/claude_desktop_config.json
{
  "mcpServers": {
    "cryptocardium": {
      "url": "https://mcp.cryptocardium.com/v1",
      "transport": "http"
    }
  }
}

Cursor / Continue / mcp-cli

# Adds the server, kicks off OAuth DCR on first connect
mcp-cli add cryptocardium \
  --url https://mcp.cryptocardium.com/v1 \
  --auth oauth

Tras autorizar en tu navegador, el agente tiene acceso a todas las herramientas del catálogo (o solo las que hayas concedido si ajustaste el alcance).

MCP · catálogo de herramientas

Las herramientas reflejan los endpoints REST. Una pequeña muestra (la lista completa está en /api):

Cuenta create_account sign_in get_account enable_2fa
Tesorería get_balance create_topup withdraw
Tarjetas issue_card load_card reveal_pan freeze_card set_card_limits
Tx & registros list_transactions get_activity file_dispute

MCP · OAuth 2.1 + DCR

Los agentes se registran dinámicamente vía RFC 7591. Flujo:

  1. El agente hace POST /oauth/register — recibe client_id & client_secret.
  2. Se solicita al usuario que autorice en el navegador (una sola vez).
  3. El agente recibe access_token (con alcance, tiempo limitado).
  4. Las solicitudes posteriores llevan el bearer JWT.

Alcances por herramienta

Restringe un agente a solo lectura, a una tarjeta específica o a un subconjunto de herramientas pasando scope= en el momento del registro. Ejemplos:

scope=read           # list & get only, no writes
scope=cards:write    # manage cards but not withdraw
scope=card:card_8f3a91b7c4d2  # single card

SDKs & ejemplos

Los SDKs oficiales llegan pronto. Mientras tanto, la API es una superficie REST plana — cualquier cliente HTTP moderno la maneja.

Node.js (fetch)

const res = await fetch('https://api.cryptocardium.com/v1/cards', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.CCM_KEY}`,
    'Idempotency-Key': `card_${crypto.randomUUID()}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    type: 'virtual', bin: '489517', load_usd: 300
  })
});
const card = await res.json();

Python (requests)

import requests, os, uuid

r = requests.post(
    'https://api.cryptocardium.com/v1/cards',
    headers={
        'Authorization': f"Bearer {os.environ['CCM_KEY']}",
        'Idempotency-Key': f"card_{uuid.uuid4()}",
    },
    json={'type': 'virtual', 'bin': '489517', 'load_usd': 300}
)
card = r.json()

PHP (curl)

$ch = curl_init('https://api.cryptocardium.com/v1/cards');
curl_setopt_array($ch, [
    CURLOPT_POST => 1,
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . $_ENV['CCM_KEY'],
        'Idempotency-Key: card_' . bin2hex(random_bytes(16)),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'type' => 'virtual',
        'bin' => '489517',
        'load_usd' => 300,
    ]),
]);
$card = json_decode(curl_exec($ch), true);

Registro de cambios

Los cambios aditivos se publican de forma transparente. Los cambios que rompen la compatibilidad van bajo un nuevo prefijo de versión.

  • 2026-05-19 · v1.4 Añadido

    POST /v1/cards/:id/load & /unload son ahora atómicos. Evento de webhook card.loaded añadido.

  • 2026-05-18 · v1.3 Añadido

    Servidor MCP activo en mcp.cryptocardium.com. DCR OAuth 2.1. Más de 40 herramientas mapeadas desde REST.

  • 2026-05-17 · v1.2 Añadido

    Programa de tarjeta Gold física (BIN 448585), 3-D Secure en Visa Business y Visa Gold.

  • 2026-05-15 · v1.1 Modificado

    Mínimo de recarga reducido a 20 $ para enrutamiento sandbox, 200 $ para raíles de producción.

  • 2026-05-12 · v1.0 Publicado

    v1 LTS. Más de 50 endpoints. Auth bearer + claves de idempotencia + webhooks HMAC.

Soporte

¿Atascado? Dos vías:

Incluye el request_id de la respuesta fallida — acelera la resolución 10 veces.

FAQ

Preguntas para desarrolladores.

Everything people actually ask. Last updated .

¿Dónde está la especificación OpenAPI?

OpenAPI 3.1 está en https://cryptocardium.com/openapi.json (JSON) y /openapi.yaml. Enlazado desde la página de inicio mediante rel="service-desc".

¿Cómo se autentican las solicitudes?

Tres opciones: (1) sesión bearer desde el inicio de sesión, (2) clave API bearer creada en /api-settings, (3) token de acceso OAuth 2.1 (recomendado para agentes de IA, admite Registro Dinámico de Clientes). Las tres se envían en la cabecera Authorization.

¿Cuál es el límite de tasa?

600 solicitudes por minuto por clave API, con una ráfaga de 100 solicitudes. Las cabeceras X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset se devuelven en cada respuesta. Límites más altos disponibles bajo petición en /contact.

¿Cómo funciona la idempotencia?

Pasa una cabecera Idempotency-Key (cualquier UUID o cadena aleatoria de 32 bytes) en POST y PATCH. Los reintentos idénticos en 24 horas devuelven la respuesta en caché. Payloads distintos con la misma clave devuelven 409 Conflict.

¿Cómo se devuelven los errores?

Cada respuesta no-2xx es { "error": "codigo_legible_por_maquina", "message": "Legible por humanos", "request_id": "req_..." }. El código de error es el identificador canónico legible por máquina; mapea la lógica de tu cliente a ese, no al mensaje.

¿Hay SDKs de cliente?

Hay ejemplos de código en cURL, JavaScript (Node + Fetch) y Python a lo largo de los docs. Los SDKs oficiales se publican a través de la organización de GitHub; los SDKs de la comunidad están enlazados desde /api.

¿Existe un entorno sandbox?

Sí. Usa una clave API de prueba desde /api-settings (con prefijo sk_test_). Todos los endpoints están replicados; las tarjetas emitidas en sandbox no se procesan en raíles de tarjetas reales.