Cryptopaid API Docs

Centralized crypto payment gateway for all your projects. One API, multiple stores, provider-agnostic.

Documentación de Cryptopaid API

Pasarela de pagos crypto centralizada para todos tus proyectos. Una API, múltiples tiendas, sin dependencia de proveedor.

Introduction Introducción

Cryptopaid is a self-hosted API that lets your projects accept cryptocurrency deposits without integrating directly with any payment provider (OxaPay, NowPayments, etc.).

When the payment provider changes or breaks, you update only Cryptopaid — your projects keep calling the same endpoints and receiving the same webhooks.

Cryptopaid es una API auto-alojada que permite a tus proyectos aceptar depósitos de criptomonedas sin integrarse directamente con ningún proveedor de pagos (OxaPay, NowPayments, etc.).

Cuando el proveedor cambia o falla, solo actualizas Cryptopaid — tus proyectos siguen llamando a los mismos endpoints y recibiendo los mismos webhooks.

Authentication Autenticación

All requests must include an Authorization header with the store API key:

Todas las solicitudes deben incluir el header Authorization con la API key de la tienda:

Authorization: Api-Key cp_live_xxxxxxxxxxxxxxxxxxxx
API keys are generated in the Admin panel when you create a store. The full key is shown only once. If you lose it, regenerate it from the Admin store action.
Las API keys se generan en el panel Admin al crear una tienda. La clave completa se muestra solo una vez. Si la pierdes, puedes regenerarla desde la acción de Admin en la tienda.

Quickstart

  1. Create a Provider Account in Admin — enter OxaPay credentials (merchant_key, general_key, payout_key) and payout settings.
  2. Create a Store — link it to the Provider Account, copy the API key.
  3. Add deposit settings on the Store (auto_convert_to, reuse_open_deposit, revoke_after_hours).
  4. Set webhook_url on the store to receive payment confirmations.
  5. Call POST /api/v1/deposits/ from your project.
  6. Show the address and qr_code to your user.
  7. Wait for the deposit.confirmed webhook — then credit your user's balance.
  8. For affiliate payouts: call POST /api/v1/withdrawals/affiliate/.
  9. For auto-sweep: enable auto_payout_enabled on the Provider Account and configure external cron.
  1. Crea una Provider Account en Admin — credenciales OxaPay y configuración de retiros.
  2. Crea una Store — vincúlala a la Provider Account, copia la API key.
  3. Configura depósitos en la Store (auto_convert_to, reuse_open_deposit, revoke_after_hours).
  4. Establece webhook_url en la tienda para recibir confirmaciones.
  5. Llama a POST /api/v1/deposits/ desde tu proyecto.
  6. Muestra address y qr_code al usuario.
  7. Espera el webhook deposit.confirmed — acredita el saldo.
  8. Para pagar afiliados: POST /api/v1/withdrawals/affiliate/.
  9. Para auto-sweep: activa auto_payout_enabled en la Provider Account y configura el cron externo.
import requests

headers = {"Authorization": "Api-Key cp_live_xxxx"}
resp = requests.post(
    "https://your-cryptopaid.up.railway.app/api/v1/deposits/",
    headers=headers,
    json={
        "external_user_id": "user_42",
        "network": "TRC20",
        "currency": "USDT",
    }
)
deposit = resp.json()
# Show deposit["address"] and deposit["qr_code"] to your user# Muestra deposit["address"] y deposit["qr_code"] a tu usuario

Create Deposit Crear Depósito

POST /api/v1/deposits/
Generates a crypto deposit address (or reuses an existing open one for the same user and network).
Genera una dirección de depósito crypto (o reutiliza una existente abierta para el mismo usuario y red).

Request body

Cuerpo de la solicitud

FieldCampo TypeTipo RequiredRequerido DescriptionDescripción
external_user_idstring required Your internal user identifier. Tu identificador interno de usuario.
networkstring required Network code: TRC20, ERC20, BTC, etc. Código de red: TRC20, ERC20, BTC, etc.
currencystring optional Token currency (required for multi-token networks like ERC20). Moneda del token (requerida para redes multi-token como ERC20).
external_referencestring optional Your own order/reference ID. Tu propio ID de orden/referencia.
metadataobject optional Arbitrary key-value data. Returned as-is in webhooks. Datos clave-valor arbitrarios. Se devuelven tal cual en los webhooks.

Response 201 Created

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "pending",
  "address": "TXyz1234567890abcdef",
  "payment_url": null,
  "qr_code": "data:image/png;base64,...",
  "network": "TRC20",
  "currency": "USDT",
  "memo": "",
  "amount_usd": null,
  "tx_hash": "",
  "external_user_id": "user_42",
  "external_reference": "",
  "expires_at": "2026-07-10T19:00:00Z",
  "metadata": {},
  "created_at": "2026-07-08T19:00:00Z"
}

List Deposits Listar Depósitos

GET /api/v1/deposits/
Returns up to 100 most recent deposits for the authenticated store.
Devuelve hasta 100 depósitos más recientes de la tienda autenticada.

Query parameters

Parámetros de consulta

ParamParámetro DescriptionDescripción
external_user_id Filter by user identifier. Filtrar por identificador de usuario.
status Filter by status: pending, paying, confirmed, expired. Filtrar por estado: pending, paying, confirmed, expired.

Get Deposit Obtener Depósito

GET /api/v1/deposits/{id}/
Returns the current state of a deposit. Use this to poll status if you don't use webhooks.
Devuelve el estado actual de un depósito. Úsalo para consultar el estado si no utilizas webhooks.

Verify Deposit Verificar Depósito

POST /api/v1/deposits/{id}/verify/
Actively queries the payment provider for the current status. Updates the deposit if payment is confirmed. Returns the updated deposit object.
Consulta activamente al proveedor de pagos el estado actual. Actualiza el depósito si el pago está confirmado. Devuelve el objeto depósito actualizado.
This makes a live request to the provider. Use it sparingly — prefer webhooks for production. If the deposit is already confirmed or expired, the provider is not queried again.
Esto realiza una solicitud en tiempo real al proveedor. Úsalo con moderación — prefiere los webhooks en producción. Si el depósito ya está confirmed o expired, no se consulta al proveedor nuevamente.

Auto Sweep (External Cron) Auto Sweep (Cron Externo)

Channel 1 — owner sweep. Withdraws balance − reserved − fee_buffer to the Provider Account's payout_address. Does not pay affiliates.

Only runs for Provider Accounts with auto_payout_enabled=true.

Canal 1 — sweep del dueño. Retira balance − reserved − fee_buffer hacia payout_address de la Provider Account. No paga afiliados.

Solo ejecuta si la Provider Account tiene auto_payout_enabled=true.

POST /internal/cron/auto-payout/

Headers

Headers

HeaderDescriptionDescripción
X-Cron-Secret Required. Must match CRON_SECRET. Requerido. Debe coincidir con CRON_SECRET.

Optional JSON body

Body JSON opcional

{ "reserved": 0, "provider_account_id": null }

Example response

Respuesta de ejemplo

{
  "processed": 1,
  "results": [{
    "account": "My OxaPay",
    "account_id": "7e6f2ca0-...",
    "ok": true,
    "balance": 500.0,
    "reserved": 125.5,
    "amount_sent": 373.5,
    "currency": "USDT",
    "withdrawal_id": "...",
    "track_id": "12345",
    "status": "submitted"
  }]
}

Affiliate Withdrawal Retiro de Afiliado

Channel 2 — affiliate payout. Your store requests a specific amount to an affiliate wallet. Requires store API key. Independent of auto_payout_enabled.

Canal 2 — pago a afiliado. Tu tienda pide un monto concreto a la wallet del afiliado. Requiere Api-Key. Independiente de auto_payout_enabled.

POST /api/v1/withdrawals/affiliate/
{
  "amount": 50,
  "address": "T...",
  "currency": "USDT",
  "network": "TRC20",
  "note": "affiliate #123",
  "external_ref": "aff_123"
}

Also: GET /api/v1/withdrawals/affiliate/ and GET /api/v1/withdrawals/affiliate/{id}/

También: GET /api/v1/withdrawals/affiliate/ y GET /api/v1/withdrawals/affiliate/{id}/

Reserved Balance URL (for auto-sweep) URL de Reserved Balance (para auto-sweep)

Before sweeping, Cryptopaid calls each linked store's reserved_balance_url (if set) to know how much to hold back (affiliates, etc.). Signed with webhook_secret.

Antes del sweep, Cryptopaid consulta reserved_balance_url de cada tienda vinculada para saber cuánto retener (afiliados, etc.). Firmado con webhook_secret.

GET {reserved_balance_url}
X-Cryptopaid-Signature: sha256=...
X-Cryptopaid-Timestamp: 1720000000

Response:
{
  "currency": "USDT",
  "affiliates_pending": 125.5,
  "other_reserved": 0,
  "as_of": "2026-07-15T03:00:00Z"
}
If a store has reserved_balance_url configured and the request fails, the sweep for that account is skipped (fail-closed).
Si una tienda tiene reserved_balance_url y la petición falla, el sweep de esa cuenta se omite (fail-closed).

Receiving Webhooks Recibir Webhooks

When a deposit is confirmed, Cryptopaid sends a POST request to your store's webhook_url with the following JSON payload:

Cuando se confirma un depósito, Cryptopaid envía una solicitud POST al webhook_url de tu tienda con el siguiente payload JSON:

{
  "event": "deposit.confirmed",
  "deposit_id": "550e8400-e29b-41d4-a716-446655440000",
  "external_user_id": "user_42",
  "external_reference": "",
  "amount_usd": "100.00",
  "tx_hash": "abc123...",
  "network": "TRC20",
  "currency": "USDT",
  "metadata": {}
}

Your endpoint must return a 2xx HTTP status. If it fails, Cryptopaid will retry up to 5 times with exponential backoff (30s → 2m → 10m → 30m → 1h).

Tu endpoint debe devolver un estado HTTP 2xx. Si falla, Cryptopaid reintentará hasta 5 veces con backoff exponencial (30s → 2m → 10m → 30m → 1h).

Verifying HMAC Signature Verificar Firma HMAC

Every webhook includes a X-Cryptopaid-Signature: sha256=<hex> header. Verify it using your store's webhook_secret before processing the payload.

Cada webhook incluye un header X-Cryptopaid-Signature: sha256=<hex>. Verifícalo usando el webhook_secret de tu tienda antes de procesar el payload.

import hashlib, hmac

def verify_signature(raw_body: bytes, header: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    received = header.removeprefix("sha256=")
    return hmac.compare_digest(expected, received)

# Django / Flask example# Ejemplo Django / Flask
raw_body = request.body          # raw bytes, NOT parsed JSON# bytes crudos, NO JSON parseado
sig_header = request.headers.get("X-Cryptopaid-Signature", "")

if not verify_signature(raw_body, sig_header, WEBHOOK_SECRET):
    return HttpResponse(status=401)

data = json.loads(raw_body)
# Process data["amount_usd"], data["external_user_id"], etc.# Procesa data["amount_usd"], data["external_user_id"], etc.
Always verify the signature before trusting the payload. Never credit a user balance based on unverified webhook data.
Siempre verifica la firma antes de confiar en el payload. Nunca acredites saldo a un usuario basándote en datos de webhook no verificados.

Status Values Estados

Status Description Descripción
pending Address generated, waiting for the user to send crypto. Dirección generada, esperando que el usuario envíe crypto.
paying Transaction detected on-chain but not yet confirmed. Transacción detectada on-chain pero aún no confirmada.
confirmed Payment fully confirmed. amount_usd is now set. Pago completamente confirmado. amount_usd ya tiene valor.
expired Address was revoked after the configured expiration period. La dirección fue revocada tras el período de expiración configurado.

Error Codes Códigos de Error

HTTP StatusEstado HTTP MeaningSignificado
400 Invalid request body or provider error. Cuerpo de solicitud inválido o error del proveedor.
401 Missing or invalid API key. API key faltante o inválida.
404 Deposit not found (or belongs to another store). Depósito no encontrado (o pertenece a otra tienda).
410 Deposit has expired — create a new one. El depósito ha expirado — crea uno nuevo.
503 Store has no active provider account. La tienda no tiene provider account activa.

Provider Variables — OxaPay Variables del Proveedor — OxaPay

Credentials and liquidity on Provider Account. Deposit settings are fields on Store.

Credenciales y liquidez en Provider Account. Depósitos en campos de Store.

Provider Account — Credentials

Provider Account — Credenciales

VariableVariable SensitiveSensible DescriptionDescripción
merchant_key 🔒 Main API key for creating deposits and static addresses. Clave API principal para crear depósitos y direcciones estáticas.
payout_key 🔒 Key with payout permissions. Required for automatic withdrawals. Clave con permisos de payout. Requerida para retiros automáticos.
general_key 🔒 General key used to query account balance. Clave general para consultar el balance de la cuenta.

Provider Account — Liquidity / sweep settings

Provider Account — Liquidez / auto-sweep

VariableVariable TypeTipo DefaultDefault DescriptionDescripción
auto_convert_to string USDT Target currency for conversion. (Store) Moneda destino. (Store)
reuse_open_deposit boolean true Reuses open deposit address. (Store) Reutiliza dirección abierta. (Store)
revoke_after_hours integer 48 Hours before address is revoked. (Store) Horas antes de revocar. (Store)
auto_payout_enabled boolean false Enables auto-sweep cron for this Provider Account. (Provider Account) Activa auto-sweep en cron. (Provider Account)
payout_address string Owner wallet for auto-sweep (not affiliates). (Provider Account) Wallet del dueño para auto-sweep. (Provider Account)
payout_currency string USDT Currency for balance/payout. (Provider Account) Moneda de balance/retiro. (Provider Account)
payout_network string Network for payouts. (Provider Account) Red de retiros. (Provider Account)
payout_fee_reserve float 1.0 Fee buffer kept in account. (Provider Account) Buffer de comisión. (Provider Account)
min_payout_amount float 1 Minimum sweep amount. (Provider Account) Monto mínimo de sweep. (Provider Account)

Admin Guide Guía de Admin

Creating a Provider Account

Crear una Provider Account

  1. Go to Admin → Provider Accounts → Add.
  2. Set name, slug, provider_slug=oxapay.
  3. Fill credentials: merchant_key, general_key, payout_key.
  4. Set payout_address and enable auto_payout_enabled only when ready for auto-sweep.
  1. Ve a Admin → Provider Accounts → Añadir.
  2. Configura name, slug, provider_slug=oxapay.
  3. Completa credenciales: merchant_key, general_key, payout_key.
  4. Configura payout_address y activa auto_payout_enabled solo cuando quieras auto-sweep.

Creating a Store

Crear una Tienda

  1. Go to Admin → Stores → Add Store.
  2. Link provider_account, set webhook_url, webhook_secret, optional reserved_balance_url.
  3. Save — copy the API key from the success message.
  4. Set deposit fields and webhooks on the Store.
  1. Ve a Admin → Stores → Añadir Store.
  2. Vincula provider_account, configura webhooks y opcional reserved_balance_url.
  3. Guarda — copia la API key del mensaje de éxito.
  4. Configura depósitos y webhooks en la Store.

Adding a New Payment Provider

Añadir un Nuevo Proveedor de Pagos

  1. Create apps/providers/<slug>/adapter.py implementing BasePaymentProvider.
  2. Register it in apps/providers/apps.pyregistry.register("slug", MyProvider).
  3. Create a Provider Account with provider_slug = <slug> in Admin.
  4. No changes needed in your client projects.
  1. Crea apps/providers/<slug>/adapter.py implementando BasePaymentProvider.
  2. Regístralo en apps/providers/apps.pyregistry.register("slug", MyProvider).
  3. Crea una Provider Account con provider_slug = <slug> en Admin.
  4. No se necesitan cambios en tus proyectos cliente.