kyoPass/API DOCS
Dashboard

Overview

kyoPass es una infraestructura de reventa de tickets white-label para LATAM. Los partners (plataformas de tickets) se integran vía API REST para habilitar un mercado secundario dentro de sus productos sin construir la infraestructura ellos mismos.

Base URL

Versión

v1

Formato

JSON (UTF-8)

Proveedores de pago

dLocal (LATAM)

Flujo general

  1. 1.Tu plataforma recibe API Key al ser aprobada como partner.
  2. 2.Creas eventos con sus funciones (schedules) y rangos de precio (priceTiers) via API.
  3. 3.Antes de abrir el widget, tu backend llama /v1/auth/federate para obtener un FCToken del usuario.
  4. 4.El widget embebido usa ese FCToken para que el usuario vea, compre y venda tickets.
  5. 5.FC notifica a tu webhook cuando una orden se paga (order.paid).

Autenticación

La API usa dos mecanismos de autenticación según el contexto de llamada.

API Key — llamadas servidor a servidor

Envía tu API Key en el header Authorization: Bearer <apiKey>. Nunca la expongas en código cliente.

http
POST /v1/auth/federate HTTP/1.1
Host: 
Authorization: Bearer kyo_live_xxxxxxxxxxxxxxxx
Content-Type: application/json

FCToken — llamadas desde el widget

Es un JWT de corta duración obtenido via /v1/auth/federate. Se pasa como Authorization: Bearer <fcToken>.

El FCToken expira en 2 horas. Genera uno nuevo antes de abrir el widget.

Partner API

Endpoints que llamas desde tu backend con Authorization: Bearer <apiKey>.

Federar usuario

POST
/v1/auth/federate

Registra o actualiza un usuario de tu plataforma y devuelve un FCToken. Llámalo desde tu backend antes de abrir el widget.

REQUEST BODY

partnerUserIdREQ
string
ID único del usuario en tu sistema.
displayNameREQ
string
Nombre visible del usuario.
email
string
Email del usuario (opcional).
phone
string
Teléfono del usuario (opcional).
bankAccount
object
Opcional. Solo necesario cuando el usuario va a vender (para recibir el payout). Un comprador puede federarse sin este campo — enviarlo después re-federando al usuario cuando decida publicar su primer ticket.

BANK ACCOUNT OBJECT

countryREQ
string
Código ISO del país (ej. GT, MX, SV).
documentREQ
string
Número de documento de identidad.
documentType
string
Tipo de documento (CC, NIT, DUI…).
accountType
string
CHECKING o SAVINGS.
accountNumberREQ
string
Número de cuenta bancaria.
bankCodeREQ
string
Código del banco (según dLocal).
bankName
string
Nombre del banco (referencia).
json — request (comprador, sin bankAccount)
{
  "partnerUserId": "usr_123",
  "displayName": "María García",
  "email": "maria@ejemplo.com"
}
json — request (vendedor, con bankAccount)
{
  "partnerUserId": "usr_123",
  "displayName": "María García",
  "email": "maria@ejemplo.com",
  "bankAccount": {
    "country": "GT",
    "document": "12345678",
    "documentType": "DPI",
    "accountType": "SAVINGS",
    "accountNumber": "0000123456",
    "bankCode": "BARED",
    "bankName": "Banrural"
  }
}

/v1/auth/federate es un upsert: puedes llamarlo primero sin bankAccount cuando el usuario solo va a comprar, y volver a llamarlo con los datos bancarios cuando decida vender. El mismo partnerUserId actualiza al usuario existente.

json — response 200
{
  "fcToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expiresIn": 7200,
  "userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

Eventos

POST
/v1/events

Crea un evento. Acepta funciones (schedules) y rangos de precio (priceTiers) en el mismo request. La moneda se hereda del partner.

GET
/v1/events

Lista todos los eventos de tu partner, incluyendo sus schedules y priceTiers.

GET
/v1/events/{id}

Obtiene un evento por ID con todos sus schedules y priceTiers.

PATCH
/v1/events/{id}

Actualiza los campos de un evento existente. Solo envía los campos que quieres cambiar.

POST /v1/events — REQUEST BODY

nameREQ
string
Nombre del evento.
venueREQ
string
Nombre del recinto (ej. Estadio Nacional).
venueAddress
string
Dirección física completa del recinto.
cityREQ
string
Ciudad del evento.
timezone
string
Timezone del recinto (ej. America/Guatemala, America/Mexico_City).
startsAtREQ
string
Fecha y hora ISO 8601 (UTC).
endsAt
string
Fecha y hora de fin ISO 8601 (opcional).
externalId
string
ID del evento en tu sistema. Garantiza idempotencia: si ya existe un evento con este ID para tu partner, se devuelve el existente sin duplicar.
description
string
Descripción del evento.
imageUrl
string
URL de imagen principal del evento.
widgetSellEnabled
boolean
Controla si los usuarios pueden publicar tickets desde el widget. false = solo el partner puede crear listings via API (el botón Vender no aparece en el widget).default: true
schedules
array
Funciones del evento. Ver objeto Schedule abajo.
priceTiers
array
Categorías de precio permitidas. Ver objeto PriceTier abajo.

PATCH /v1/events/{id} — REQUEST BODY

Todos los campos son opcionales. Solo se actualizan los que envíes.

name
string
Nuevo nombre del evento.
venue
string
Nuevo recinto.
venueAddress
string
Nueva dirección.
city
string
Nueva ciudad.
timezone
string
Nuevo timezone.
description
string
Nueva descripción.
imageUrl
string
Nueva URL de imagen.
startsAt
string
Nueva fecha y hora ISO 8601.
widgetSellEnabled
boolean
Habilita o deshabilita la venta desde el widget para este evento.

widgetSellEnabled: cuando es false, el endpoint POST /v1/listings rechaza requests con FCToken (widget users) con error 403. Los listings solo pueden crearse via POST /v1/partner/listings usando API Key. Útil cuando la ticketera quiere controlar el inventario disponible para reventa.

Objeto Schedule (función)

Un evento puede tener múltiples schedules para tours, residencias o eventos con varias fechas. Si el evento tiene schedules, los vendedores deben indicar el scheduleId al crear un listing.

titleREQ
string
Título de la función (ej. Noche 1, Guatemala City).
startsAtREQ
string
Fecha y hora de esta función, ISO 8601.
externalShowId
string
ID de este show en tu sistema.
ticketingUrl
string
URL de compra original de esta función.
resaleEnabled
boolean
false deshabilita la reventa para esta fecha específica (ej. noche de estreno, función de gala).default: true

Objeto PriceTier (categoría de precio)

Define las categorías de precio permitidas. Si el evento tiene priceTiers, los vendedores deben seleccionar uno al publicar un ticket. El sistema valida que el precio esté dentro del rango permitido.

nameREQ
string
Nombre del tier (ej. General, VIP, Palco).
amountREQ
number
Precio de referencia / valor facial en unidades enteras (ej. 15000 = Q150.00).
description
string
Descripción adicional del tier.
sortOrder
number
Orden de presentación ascendente.default: 0
externalPriceTypeId
string
ID de este tier en tu sistema (para reconciliación).
minResalePrice
number
Precio mínimo de reventa. Si es null, se usa amount como piso.
maxResalePrice
number
Precio máximo de reventa. Si es null, no hay techo.

Los precios con rangos permiten flexibilidad: un vendedor puede publicar a cualquier precio entre minResalePrice y maxResalePrice. Si no se definen rangos, el precio del tier es exactamente amount.

json — request completo con schedules y priceTiers
{
  "name": "Bad Bunny — World Hottest Tour",
  "venue": "Estadio Doroteo Guamuch Flores",
  "venueAddress": "Av. Las Américas 16-01, Zona 13, Ciudad de Guatemala",
  "city": "Guatemala City",
  "timezone": "America/Guatemala",
  "startsAt": "2026-03-15T20:00:00Z",
  "externalId": "EVT-BB-GT-2026",
  "imageUrl": "https://cdn.miplataforma.com/events/bad-bunny-gt.jpg",
  "widgetSellEnabled": true,
  "schedules": [
    {
      "title": "Noche 1 — 15 marzo",
      "startsAt": "2026-03-15T20:00:00Z",
      "externalShowId": "SHOW-001",
      "ticketingUrl": "https://miplataforma.com/eventos/bad-bunny-noche-1",
      "resaleEnabled": true
    },
    {
      "title": "Noche 2 — 16 marzo",
      "startsAt": "2026-03-16T20:00:00Z",
      "externalShowId": "SHOW-002",
      "ticketingUrl": "https://miplataforma.com/eventos/bad-bunny-noche-2",
      "resaleEnabled": true
    },
    {
      "title": "Noche Extra VIP — 17 marzo",
      "startsAt": "2026-03-17T20:00:00Z",
      "externalShowId": "SHOW-003",
      "resaleEnabled": false
    }
  ],
  "priceTiers": [
    {
      "name": "General",
      "amount": 35000,
      "description": "Acceso general de pie",
      "sortOrder": 1,
      "externalPriceTypeId": "PT-GEN",
      "minResalePrice": 35000,
      "maxResalePrice": 70000
    },
    {
      "name": "VIP",
      "amount": 75000,
      "description": "Zona VIP con vista privilegiada",
      "sortOrder": 2,
      "externalPriceTypeId": "PT-VIP",
      "minResalePrice": 75000,
      "maxResalePrice": 150000
    },
    {
      "name": "Palco",
      "amount": 120000,
      "description": "Palco privado para grupos",
      "sortOrder": 3,
      "externalPriceTypeId": "PT-PAL"
    }
  ]
}
json — response 201
{
  "eventId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "createdAt": "2026-01-10T15:00:00Z",
  "schedules": [
    {
      "id": "sch_aaa...",
      "title": "Noche 1 — 15 marzo",
      "startsAt": "2026-03-15T20:00:00Z",
      "externalShowId": "SHOW-001",
      "status": "active",
      "resaleEnabled": true
    },
    {
      "id": "sch_bbb...",
      "title": "Noche Extra VIP — 17 marzo",
      "startsAt": "2026-03-17T20:00:00Z",
      "status": "active",
      "resaleEnabled": false
    }
  ],
  "priceTiers": [
    {
      "id": "pt_111...",
      "name": "General",
      "amount": 35000,
      "currency": "GTQ",
      "externalPriceTypeId": "PT-GEN",
      "minResalePrice": 35000,
      "maxResalePrice": 70000,
      "sortOrder": 1
    }
  ]
}

Perfil y transacciones

GET
/v1/partner/profile

Devuelve el perfil del partner autenticado.

GET
/v1/partner/transactions

Lista las órdenes pagadas del partner. Soporta ?limit= y ?offset=.

json — GET /v1/partner/profile response
{
  "id": "...",
  "name": "Mi Plataforma",
  "slug": "mi-plataforma",
  "country": "GT",
  "currency": "GTQ",
  "commissionPct": 0.10,
  "status": "active",
  "webhookUrl": "https://mi-sitio.com/webhooks/fc",
  "createdAt": "2025-01-01T00:00:00Z"
}

Widget / User API

Endpoints que llama el widget embebido con el FCToken del usuario viaAuthorization: Bearer <fcToken>. No los llames desde tu backend.

Listings (usuario final · JWT)

Rutas que llama el vendedor con su fcToken (obtenido vía /auth/federate). Úsalas cuando el botón "Vender ticket" está en el frontend del partner y llama directamente a FC.

GET
/v1/listings

Lista tickets disponibles. Filtra por eventId, scheduleId, minPrice, maxPrice, limit, offset.

GET
/v1/listings/{id}

Obtiene un listing específico.

POST
/v1/listings

El vendedor publica un ticket para vender.

PATCH
/v1/listings/{id}

El vendedor actualiza precio, notas o datos del ticket.

DELETE
/v1/listings/{id}

El vendedor cancela/retira su ticket del mercado.

POST /v1/listings — REQUEST BODY

eventIdREQ
string
UUID del evento.
scheduleId
string
UUID de la función. Requerido si el evento tiene schedules.
priceTierId
string
UUID del price tier. Requerido si el evento tiene priceTiers.
seatSectionREQ
string
Sección/zona del asiento (ej. General, VIP, Platea).
seatRow
string
Fila del asiento.
seatNumber
string
Número de asiento. Cuando quantity > 1, debe contener la lista de asientos separados por coma: "12, 13, 14". La cantidad de asientos debe coincidir con quantity. Vacío = general admission.
basePriceAmount
number
Precio de venta en centavos. Si hay priceTierId, debe estar dentro del rango [minResalePrice, maxResalePrice].
quantity
number
Número total de tickets en este listing (default 1). Si > 1, el listing es multi-ticket y el comprador puede adquirir varios a la vez.
splitType
string
Regla de compra para multi-ticket: "ANY" (cualquier cantidad, default) | "TOGETHER" (todos juntos) | "AVOID_ONE" (nunca dejar 1 suelto) | "AVOID_ONE_THREE" (nunca dejar 1 ni 3 sueltos) | "AVOID_ODD" (solo números pares).
externalTicketId
string
ID del ticket en el sistema del partner (para tracking).
notes
string
Notas visibles para el comprador.
ticketLocator
string
Código QR / barcode del ticket (para validación digital en puerta).
ticketAccessType
string
Tipo de acceso: "QR" | "BARCODE" | "NFC" | "OTHER".
faceValueAmount
number
Precio original de compra del ticket en centavos (informativo para el comprador).
holderName
string
Nombre del titular del ticket (para tickets nominales).
holderDocument
string
Documento del titular del ticket.
holderDocumentType
string
Tipo de documento: "DNI" | "CI" | "CPF" | "Passport" | etc.
isNominal
boolean
true si el ticket está emitido a nombre específico y requiere presentar ID.
json — ejemplo mínimo
{
  "eventId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "seatSection": "General",
  "seatRow": "A",
  "seatNumber": "12",
  "basePriceAmount": 120000,
  "ticketLocator": "QR-A1B2C3D4E5",
  "ticketAccessType": "QR"
}
json — ejemplo multi-ticket (3 asientos contiguos)
{
  "eventId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "seatSection": "Platea",
  "seatRow": "B",
  "seatNumber": "12, 13, 14",
  "basePriceAmount": 150000,
  "quantity": 3,
  "splitType": "TOGETHER"
}
json — ejemplo completo (ticket nominal)
{
  "eventId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "scheduleId": "sch_aaa...",
  "priceTierId": "pt_111...",
  "seatSection": "VIP",
  "seatRow": "B",
  "seatNumber": "7",
  "basePriceAmount": 350000,
  "faceValueAmount": 350000,
  "externalTicketId": "TKT-99812",
  "ticketLocator": "QR-VIP-XYZXYZXYZ",
  "ticketAccessType": "QR",
  "holderName": "María González",
  "holderDocument": "12345678",
  "holderDocumentType": "CI",
  "isNominal": true,
  "notes": "Ticket digital con acceso VIP"
}

PATCH /v1/listings/{id} — REQUEST BODY (todos opcionales)

priceAmount
number
Nuevo precio de venta en centavos.
notes
string
Actualiza las notas del listing.
ticketLocator
string
Actualiza el código QR/barcode.
ticketAccessType
string
Actualiza el tipo de acceso.
holderName
string
Actualiza el nombre del titular.
holderDocument
string
Actualiza el documento del titular.
holderDocumentType
string
Actualiza el tipo de documento.

Si el evento tiene schedules configurados, scheduleId es obligatorio y debe corresponder a una función con resaleEnabled: true. Si la función tiene resaleEnabled: false, el listing será rechazado.

Si el evento tiene priceTiers, priceTierId es obligatorio. El precio basePriceAmount debe estar dentro del rango [minResalePrice, maxResalePrice] del tier. Si se omite, se usa el precio mínimo del tier.

Multi-ticket: cuando publiques un listing con quantity > 1, seatNumber debe listar todos los asientos separados por coma (ej: "12, 13, 14" para 3 entradas). El backend valida que la cantidad de asientos coincida con quantity y normaliza el formato. Si no hay asiento asignado (general admission), deja seatNumber vacío independientemente de la cantidad. splitType controla cómo se pueden comprar: TOGETHER fuerza que se lleven todos, ANY permite comprar cualquier subconjunto.

Listings (backend del partner · API Key)

Rutas para que el backend del partner gestione listings en nombre de sus usuarios. Úsalas cuando tu sistema tiene los datos de los tickets y quieres sincronizar el estado con FC automáticamente (botón server-side, cambios de estado desde tu CMS, etc.).

GET
/v1/partner/listings

Lista todos los listings de los eventos de este partner. Filtra por eventId, scheduleId, status, minPrice, maxPrice.

POST
/v1/partner/listings

Crea un listing en nombre de un usuario (partnerUserId).

PATCH
/v1/partner/listings/{id}

Actualiza un listing (precio, locator, datos del titular). El partner puede actualizar cualquier listing suyo.

DELETE
/v1/partner/listings/{id}

Cancela un listing. Úsalo cuando el ticket ya no está disponible en tu sistema.

POST /v1/partner/listings — REQUEST BODY

partnerUserIdREQ
string
ID del vendedor en el sistema del partner. FC lo convierte en un sellerId interno reproducible.
eventIdREQ
string
UUID del evento en FC.
scheduleId
string
UUID de la función (requerido si el evento tiene schedules).
priceTierId
string
UUID del price tier (requerido si el evento tiene priceTiers).
seatSectionREQ
string
Sección/zona del asiento.
seatRow
string
Fila del asiento.
seatNumber
string
Número de asiento. Cuando quantity > 1, debe contener la lista separada por coma: "12, 13, 14" (la cantidad debe coincidir con quantity).
basePriceAmount
number
Precio de venta en centavos.
quantity
number
Número total de tickets (default 1).
splitType
string
Regla de compra multi-ticket: "ANY" | "TOGETHER" | "AVOID_ONE" | "AVOID_ONE_THREE" | "AVOID_ODD".
externalTicketId
string
ID del ticket en tu sistema (útil para encontrarlo luego con PATCH/DELETE).
ticketLocator
string
Código QR / barcode.
ticketAccessType
string
"QR" | "BARCODE" | "NFC" | "OTHER".
faceValueAmount
number
Precio de compra original en centavos.
holderName
string
Nombre del titular.
holderDocument
string
Documento del titular.
holderDocumentType
string
Tipo de documento.
isNominal
boolean
true si el ticket es nominal.
notes
string
Notas para el comprador.
json — POST /v1/partner/listings
{
  "partnerUserId": "user-123",
  "eventId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "scheduleId": "sch_aaa...",
  "priceTierId": "pt_111...",
  "seatSection": "General",
  "seatRow": "A",
  "seatNumber": "15",
  "basePriceAmount": 120000,
  "faceValueAmount": 120000,
  "externalTicketId": "TKT-88821",
  "ticketLocator": "QR-GEN-ABC123",
  "ticketAccessType": "QR",
  "holderName": "Carlos Pérez",
  "holderDocument": "87654321",
  "holderDocumentType": "DNI",
  "isNominal": false,
  "notes": "Ticket digital, entrega vía email"
}

El partnerUserId se usa para generar un sellerId interno reproducible (UUID v5). No necesitas federar al usuario previamente para crear listings desde el backend. Sin embargo, si el usuario quiere recibir payouts, sí deberá estar federado con datos bancarios.

Flujo de compra

POST
/v1/listings/{id}/intention

Paso 1: Crea una intención de compra. Reserva el listing por 10 minutos y devuelve el precio final con comisión aplicada.

POST
/v1/orders

Paso 2: Confirma la orden con datos del pagador. Devuelve un paymentUrl de dLocal.

GET
/v1/orders/{id}

Obtiene el estado de una orden.

POST
/v1/orders/{id}/sync

Consulta dLocal y sincroniza el estado del pago (útil en desarrollo sin webhook).

POST /v1/orders — REQUEST BODY

intentionIdREQ
string
ID devuelto por /intention.
paymentMethodREQ
string
Método de pago dLocal (ej. CARD, BANK_TRANSFER).
payerNameREQ
string
Nombre completo del comprador.
payerEmailREQ
string
Email del comprador.
payerPhone
string
Teléfono del comprador.
payerDocument
string
Documento de identidad del comprador.
countryREQ
string
Código ISO 2 del país del comprador (ej. GT, MX).
json — POST /v1/orders request
{
  "intentionId": "550e8400-e29b-41d4-a716-446655440000",
  "paymentMethod": "CARD",
  "payerName": "Juan López",
  "payerEmail": "juan@ejemplo.com",
  "payerPhone": "+50212345678",
  "payerDocument": "12345678",
  "country": "GT"
}
json — response 201
{
  "orderId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "paymentUrl": "https://sandbox.dlocal.com/collect/pay?...",
  "total": 16500,
  "currency": "GTQ",
  "expiresAt": "2025-04-10T16:00:00Z"
}

Redirige al usuario al paymentUrl. dLocal procesará el pago y notificará al webhook configurado.

Historial del usuario

GET
/v1/users/me/listings

Tickets que el usuario tiene publicados para venta.

GET
/v1/users/me/orders

Órdenes de compra del usuario.

GET
/v1/users/me/payouts

Pagos recibidos por ventas completadas.

Webhooks salientes

FC envía un POST a tu webhookUrl cuando ocurren eventos importantes. Configura la URL en tu perfil de partner.

Evento: order.paid

Se dispara cuando una orden es confirmada como pagada por dLocal.

json — POST {webhookUrl}
{
  "event": "order.paid",
  "orderId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "listingId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "buyerId": "...",
  "sellerId": "...",
  "amount": 16500,
  "currency": "GTQ",
  "paymentId": "PAY-dlocal-abc123"
}

Verificación de firma

Cada request incluye el header X-FC-Signature. Verifica la firma para validar que proviene de FC.

node.js — verificación
const crypto = require('crypto')

function verifyWebhook(rawBody, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex')
  return `sha256=${expected}` === signature
}

// En tu handler:
app.post('/webhooks/fc', (req, res) => {
  const sig = req.headers['x-fc-signature']
  const raw = req.rawBody // Buffer sin parsear

  if (!verifyWebhook(raw, sig, process.env.FC_WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature')
  }

  const { event, orderId } = req.body
  if (event === 'order.paid') {
    // Tu lógica aquí
  }
  res.sendStatus(200)
})

FC reintenta la entrega hasta 3 veces con backoff exponencial de 2 segundos si tu endpoint responde con status != 2xx.

Onboarding

Endpoint público para solicitar acceso como partner. No requiere autenticación.

POST
/v1/onboarding

Envía una solicitud de integración. Un admin la revisará y aprobará en 24–48 horas.

REQUEST BODY

nameREQ
string
Nombre de tu empresa.
slugREQ
string
Identificador único. Solo letras minúsculas, números y guiones.
countryREQ
string
Código ISO del país principal (GT, MX, SV…).
currencyREQ
string
Moneda principal (GTQ, MXN, USD…).
contactEmailREQ
string
Email donde recibirás tu API Key al ser aprobado.
webhookUrl
string
URL donde recibirás notificaciones (se puede agregar después).
json — request
{
  "name": "MiPlataforma Guatemala",
  "slug": "miplataforma-gt",
  "country": "GT",
  "currency": "GTQ",
  "contactEmail": "dev@miplataforma.com",
  "webhookUrl": "https://miplataforma.com/webhooks/fc"
}
json — response 201
{
  "id": "...",
  "name": "MiPlataforma Guatemala",
  "status": "pending",
  "message": "Solicitud recibida. Te contactaremos a dev@miplataforma.com."
}

Pagos & payouts

kyoPass procesa cobros y payouts a través de un único proveedor regional. Esta sección resume las reglas operativas que condicionan qué usuarios pueden cobrar y en qué países. Si tu integración sólo recibe compradores (no paga a vendedores), sólo te afecta la sección de países/monedas.

Proveedor: dLocal

Todo el flujo de pago corre sobre dLocal. Los compradores pagan con los métodos locales del país (tarjetas, Pix, OXXO, Yappy, transferencia bancaria, etc.) y los vendedores reciben el payout por transferencia bancaria directa a su cuenta.

Futuros proveedores: la integración está detrás de un puerto (port.PaymentService). Podemos sumar otros procesadores (ej. Stripe Connect para US/EU) sin romper el contrato de la API.

Países y monedas soportadas

Estos son los países donde dLocal puede emitir payouts a cuentas bancarias. El campo country de bankAccount debe ser uno de esta lista (ISO 3166-1 alpha-2). La moneda local se usa por defecto; si el evento está en otra moneda, el payout se convierte vía USD (flujo P2P/REMITTANCE).

ISOPAÍSMONEDA
GTGuatemalaGTQ
MXMéxicoMXN
BRBrasilBRL
ARArgentinaARS
COColombiaCOP
PEPerúPEN
CLChileCLP
UYUruguayUYU
SVEl SalvadorUSD
HNHondurasHNL
CRCosta RicaCRC
PAPanamáPAB
NINicaraguaNIO
DORep. DominicanaDOP
ECEcuadorUSD
BOBoliviaBOB
PYParaguayPYG
USEstados UnidosUSD

Cross-border (P2P): si la moneda del evento no coincide con la moneda local del beneficiario (ej. evento en GTQ pero payout a MX), el payout se convierte primero a USD y luego a la moneda destino. Requiere que la tasa de cambio origen → USD esté configurada en el backend (usdRates). Sin esa tasa, el payout falla con el error "tasa FX no configurada".

Reglas para la cuenta del beneficiario

Para que un vendedor reciba payouts, su registro FederatedUser debe incluir el objeto bankAccount con datos válidos. Si el bankAccount falta o tiene datos inválidos, las ventas se completan igual pero el payout queda en estado failed y no se libera el dinero al vendedor.

  • ·

    Titular = beneficiario

    El nombre del titular de la cuenta bancaria debe coincidir con el displayName del usuario federado. dLocal rechaza el payout si el nombre no matchea.

  • ·

    Documento válido del país

    El document + documentType deben ser de la misma persona titular y del mismo país que la cuenta. Ver sección de documentos por país.

  • ·

    Tipo de cuenta soportado

    accountType: "CHECKING" (cuenta corriente/monetaria) o "SAVINGS" (cuenta de ahorro). Default: CHECKING.

  • ·

    Código de banco de dLocal

    bankCode debe ser un identificador que dLocal reconozca. Varía por país (ej. GT: BARED para Banrural, BDAG para Agromercantil). Consulta la tabla de códigos de dLocal o usa el endpoint de lookup.

  • ·

    Cuenta propia

    La cuenta debe ser del mismo titular federado, no de un tercero. En cross-border (P2P) esto aplica estrictamente — dLocal valida el CURP/RFC/DPI contra la titularidad.

  • ·

    Mayoría de edad

    El titular debe ser mayor de 18 años en su país. dLocal valida esto contra el documento.

Payout scheduling: los payouts no se emiten al instante. Se agregan a la cola cuando la orden pasa a completed y se procesan por un job diario (/internal/jobs/process-payouts). El vendedor recibe el dinero en su cuenta en 24–72h hábiles una vez liberado el payout, según su banco local.

Tipo de documento por país

Si no envías documentType en el bankAccount, el backend asume el tipo por defecto según el país. Puedes enviar cualquiera de los tipos reconocidos; si el tipo es desconocido, se normaliza a OTHER.

PAÍSDOCUMENTOdocumentType
GTDPI (Documento Personal de Identificación)DPI
MXRFC (Registro Federal de Contribuyentes)RFC
BRCPF (Cadastro de Pessoas Físicas)CPF
ARCUIL / CUITCUIL
COCédula de CiudadaníaCC
PEDNIDNI
CLRUTRUT
UYCédula de IdentidadCI
SVDUIDUI
HNDNIDNI
CRCédula de IdentidadCI
PACédula de IdentidadCI
DOCédula de IdentidadCI
ECCédula de IdentidadCI
BOCédula de IdentidadCI
PYCédula de IdentidadCI

Tipos adicionales aceptados: PASSPORT, CE (Cédula de Extranjería CO), NIT, RUC, CUIT, CUI, OTHER.

Códigos de banco

El campo bankCode del bankAccount es un string de 3–5 caracteres definido por dLocal. Cada país tiene su propia lista — no hay formato universal. Abajo los códigos más comunes por país. Para la lista completa y actualizada consulta la documentación oficial de dLocal.

GUATEMALA (GT)

BAREDBanrural
BDAGBanco Agromercantil (BAM)
BIDUSBanco Industrial
BGTCG&T Continental
CHNGTBanco de los Trabajadores
BANPRBanco Promerica

MÉXICO (MX)

BBVAMBBVA México
BANMXBanamex
SANMXSantander México
BNRMXBanorte
HSBMXHSBC México
SCOMXScotiabank México

COLOMBIA (CO)

BANCOBancolombia
BBOGBanco de Bogotá
DAVDavivienda
BBVACBBVA Colombia
BPOPBanco Popular
NEQUINequi

BRASIL (BR)

ITAUItaú
BBBanco do Brasil
BRADBradesco
SANBRSantander Brasil
CEFCaixa Econômica
NUNubank

Cómo obtener el código: en el widget de onboarding del vendedor, mostramos un selector con los bancos disponibles del país seleccionado y mapeamos al bankCode de dLocal automáticamente. Si integras el sell-flow desde tu propio frontend, usa un selector similar — no dejes que el usuario escriba el código a mano.

Errores

Todos los errores devuelven JSON con el campo error.

json — error response
{
  "error": "listing not available"
}
400Bad RequestParámetros inválidos. Ej: precio fuera del rango del tier, scheduleId inválido, resaleEnabled: false.
401UnauthorizedAPI Key o FCToken inválido/expirado.
403ForbiddenSin permisos para este recurso.
404Not FoundRecurso no encontrado.
409ConflictEl listing ya fue vendido o reservado.
500Server ErrorError interno. Reintentar con backoff.

FC SECONDARY MARKET — API v1 — 2026