Saltar al contenido principal

Integración Payments

La integración Payments es una API REST agnóstica de proveedor para las operaciones financieras esenciales que todo backoffice necesita:
  1. Emitir Invoice (cobro)POST /payments/invoices. Una Invoice aquí es una solicitud de pago — un cobro recolectado vía PIX, boleto, tarjeta, ACH o SEPA según la región.
  2. Cancelar InvoicePOST /payments/invoices/{id}/cancel (anula cobros no pagados).
  3. Emitir documento fiscal (NFS-e/NF-e/PEPPOL)POST /payments/invoices/{id}/tax-documents. Opcional, específico por región (Brasil hoy, Europa después). También puede ser auto-emitido al crear la Invoice.
  4. Pagar a beneficiario (premio o cualquier payout)POST /payments/payouts.
  5. Leer un extracto bancarioGET /payments/balance-transactions.
Toda transacción lleva campos de control de primer nivel usados por tu equipo financiero para conciliación: cost_center (centro de costos) y contractor_reference (referencia del contratante) los envías en el request; our_number (nuestro número) lo genera SalesOS y se devuelve en el response (y en cada movimiento del extracto). Por debajo, SalesOS rutea la solicitud al proveedor correcto — no necesitas elegir el proveedor a menos que quieras.
Cobro ≠ documento fiscal. Una Invoice es la solicitud de pago (boleto, PIX, tarjeta). El documento fiscal (NFS-e en BR, PEPPOL en UE) es un recurso separado y opcional adjunto a la Invoice. Esta separación mantiene la API portable entre BR / US / UE.
La API sigue convenciones de mercado: modelo REST por recurso, montos en unidades menores enteras, timestamps ISO-8601, RFC 9457 Problem Details para errores, header Idempotency-Key para reintentos seguros, paginación por cursor y webhooks firmados. Si ya integraste con cualquier API moderna de pagos, te sentirás como en casa.

Ruteo por Región

SalesOS elige el backend correcto automáticamente a partir de customer.country y currency. No necesitas escoger.
País del clienteMonedaEstadoMétodos
BRBRLactivopix, boleto, bolepix, card (card-as-PIX)
USUSDpróximamentecard, ach_debit, bank_transfer
Estados miembros UEEUR / localpróximamentecard, sepa_debit, bank_transfer
RegiónTipo de documento fiscalEstado
BRnfse (servicios)activo
BRnfe (productos)próximamente
UEpeppol (e-invoice)próximamente
USn/asales tax via metadata de la Invoice; sin documento fiscal
Los payouts rutean por destino: BRL → PIX cashout; otras monedas → transferencia internacional.

Cómo Funciona

  1. Obtienes una API Key en el Dashboard de SalesOS (Admin > Integraciones > API Keys) con los scopes correctos (payments:write, payments:read).
  2. Emites Invoices (cobros). SalesOS crea la solicitud de pago en la región del cliente (BR activo; US/UE próximamente). Recibes un artefacto pagable: QR-code/copia-pega PIX, código de barras de boleto, URL de checkout de tarjeta.
  3. (Opcional) Se adjunta un documento fiscal. Cuando currency = BRL y configuras tax_document.auto_issue: true, SalesOS emite una NFS-e automáticamente tras la confirmación del pago. También puedes llamar a POST /invoices/{id}/tax-documents después para emitir o reintentar.
  4. Pagas a beneficiarios (empleados, partners, ganadores de premios). SalesOS rutea pagos BRL via PIX y otras monedas via transferencia internacional.
  5. Lees un extracto unificado — toda factura, payout, comisión y fee de documento fiscal en un único libro mayor, filtrable por cost_center, our_number, contractor_reference, período y proveedor.
  6. Escuchas webhooks para eventos terminales (invoice.paid, invoice.canceled, tax_document.issued, payout.paid, …) en lugar de hacer polling.

Inicio Rápido

1

Obtener tu API Key

Ve a Admin > Integraciones > API Keys en el Dashboard de SalesOS. Crea una nueva clave con los scopes payments:write y payments:read. Copia la clave — solo se mostrará una vez.Tu clave luce así: sk_live_a1b2c3d4e5f6g7h8i9j0...
2

Emite tu primera Invoice (BR — cobro PIX con NFS-e automática)

Crea un cobro PIX para un cliente brasileño. El bloque opcional tax_document indica a SalesOS que emita la NFS-e automáticamente tras el pago.
curl -X POST https://api.play2sell.com/functions/v1/payments/invoices \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Idempotency-Key: inv-2026-04-27-001" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": {
      "country": "BR",
      "tax_id": "12345678000190",
      "name": "Acme Corp Ltda",
      "email": "billing@acme.com.br"
    },
    "amount": 12345,
    "currency": "BRL",
    "description": "Consultoría — Abril/2026",
    "payment_method": { "type": "pix", "expires_in_seconds": 3600 },
    "tax_document": {
      "auto_issue": true,
      "type": "nfse",
      "service_code": "01.05"
    },
    "cost_center": "CC-OPERATIONS",
    "contractor_reference": "PO-9981",
    "metadata": { "campaign": "spring-2026", "owner_user_id": "usr-7782" }
  }'
Respuesta (201 Created):
{
  "id": "inv_01HW1Z3K8C7G6Y9PQ4M5R2X0NA",
  "status": "open",
  "amount": 12345,
  "currency": "BRL",
  "region": "br",
  "payment_method": {
    "type": "pix",
    "pix": {
      "qr_code": "00020126580014br.gov.bcb.pix...",
      "qr_code_image_url": "https://api.play2sell.com/.../qr.png",
      "expires_at": "2026-04-27T15:00:00Z"
    }
  },
  "tax_document": {
    "id": "txd_01HW1Z3K8C7G6Y9PQ4M5R2X0NX",
    "type": "nfse",
    "status": "pending",
    "auto_issue": true
  },
  "cost_center": "CC-OPERATIONS",
  "our_number": "INV-2026-000123",
  "contractor_reference": "PO-9981",
  "metadata": { "campaign": "spring-2026", "owner_user_id": "usr-7782" },
  "created": "2026-04-27T14:00:00Z"
}
El status pasa por openpaid (en la confirmación PIX, ~segundos) → tax_document.status: issued (emisión de NFS-e, segundos a minutos). Escucha los webhooks invoice.paid y tax_document.issued en vez de hacer polling.
3

(Opcional) Emite una Invoice para cliente US (próximamente)

Para clientes US/UE SalesOS rutea el cobro hacia el backend internacional. Esta ruta queda en cola tras el onboarding de Play2Sell LLC — las llamadas hoy devuelven 501 provider_not_configured.
curl -X POST https://api.play2sell.com/functions/v1/payments/invoices \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Idempotency-Key: inv-us-2026-04-27-001" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": {
      "country": "US",
      "name": "Acme Inc",
      "email": "billing@acme.com"
    },
    "amount": 12345,
    "currency": "USD",
    "description": "Consulting services — April/2026",
    "payment_method": { "type": "card" },
    "cost_center": "CC-OPERATIONS",
    "contractor_reference": "PO-9981"
  }'
Sin bloque tax_document — US no tiene documento fiscal nacional. Sales tax va en metadata o futuros line_items. El SSN del cliente no se recoge en este endpoint: los cobros B2C/B2B regulares en EE.UU. no lo requieren. El manejo de SSN/EIN para reporting 1099 (cuando pagas a contractors US) es un flujo separado en Payouts, no en Invoices.
4

Pagar a un beneficiario

Paga a un ganador de premio via PIX (BRL — ruteo automático):
curl -X POST https://api.play2sell.com/functions/v1/payments/payouts \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Idempotency-Key: payout-2026-04-27-001" \
  -H "Content-Type: application/json" \
  -d '{
    "beneficiary": {
      "name": "Maria Santos",
      "document": "12345678901",
      "phone": "+5511999000111",
      "email": "maria@example.com",
      "bank_account": { "type": "pix", "key_type": "cpf", "key": "12345678901" }
    },
    "amount": 50000,
    "currency": "BRL",
    "purpose": "prize",
    "cost_center": "CC-AWARDS",
    "contractor_reference": "EVENT-Q2-WINNER-12",
    "metadata": { "event_id": "evt-2026-q2", "user_id": "usr-1101" }
  }'
Respuesta (201 Created):
{
  "id": "po_01HW1Z9P7B5F2X8KQ4M5R2X0NB",
  "status": "processing",
  "amount": 50000,
  "currency": "BRL",
  "region": "br",
  "cost_center": "CC-AWARDS",
  "our_number": "PO-2026-000045",
  "contractor_reference": "EVENT-Q2-WINNER-12",
  "created": "2026-04-27T14:05:00Z"
}
Recibirás un webhook payout.paid en segundos en sandbox o en menos de un minuto en producción (PIX).
5

Leer tu extracto

Lista cada movimiento etiquetado con cost_center=CC-AWARDS del mes:
curl -X GET "https://api.play2sell.com/functions/v1/payments/balance-transactions?cost_center=CC-AWARDS&created[gte]=2026-04-01&created[lte]=2026-04-30&limit=50" \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
Respuesta (200 OK):
{
  "data": [
    {
      "id": "btxn_01HW1Z9P7B5F2X8KQ4M5R2X0NC",
      "type": "payout",
      "amount": -50000,
      "currency": "BRL",
      "net": -50100,
      "fee": 100,
      "available_on": "2026-04-27",
      "created": "2026-04-27T14:05:30Z",
      "source": { "resource": "payout", "id": "po_01HW1Z9P7B5F2X8KQ4M5R2X0NB" },
      "cost_center": "CC-AWARDS",
      "our_number": "PO-2026-000045",
      "contractor_reference": "EVENT-Q2-WINNER-12"
    }
  ],
  "has_more": false
}

Autenticación

Todas las solicitudes requieren una API Key en el header Authorization:
Authorization: Bearer sk_live_YOUR_API_KEY
Consulta la página de Autenticación para detalles sobre cómo crear y administrar API Keys.
PropiedadDetalles
HeaderAuthorization: Bearer sk_live_xxx
Scopespayments:write (crear/cancelar), payments:read (listar/consultar)
Límite de solicitudesConfigurable por clave (por defecto: 1000 solicitudes/hora)
Formato de clavesk_live_ (producción) o sk_test_ (pruebas)

Entornos

URL Base: https://api.play2sell.comDashboard: https://dashboard.play2sell.com

Referencia de Endpoints

Path base: /functions/v1/payments. Todos los endpoints aceptan y devuelven JSON.

Invoices (Cobros)

Una Invoice es un cobro — una solicitud de pago que se recolectará de tu cliente vía PIX, boleto, tarjeta u otro método según la región. La Invoice no incluye un documento fiscal por defecto; ver Tax Documents abajo.

POST /functions/v1/payments/invoices — crear un cobro

customer
object
requerido
Cliente que será cobrado.
customer.country
string
requerido
ISO-3166-1 alpha-2 (BR, US, DE, …). Decide el ruteo de proveedor.
customer.tax_id
string
CPF (11 dígitos) o CNPJ (14 dígitos) para BR (obligatorio cuando tax_document está presente). Para cobros US/UE este campo no es obligatorio — déjalo fuera salvo que tu flujo contable lo necesite. SSN/EIN no se recolectan aquí en cobros normales.
customer.name
string
requerido
Razón social o nombre completo (max 255 caracteres).
customer.email
string
requerido
Email válido — se usa para recibos y (cuando aplique) la entrega del documento fiscal.
amount
integer
requerido
Monto total en unidades menores (ej: 12345 = R$ 123,45). Debe ser positivo.
currency
string
requerido
Código ISO-4217. Decide el ruteo de proveedor junto con customer.country.
description
string
requerido
Descripción que aparece en el artefacto de pago y (cuando se emite) en la discriminación del documento fiscal (max 1000 caracteres).
El campo description se muestra al pagador. En cobros PIX aparece en la app bancaria/billetera del pagador junto al código QR; en boleto se imprime en el comprobante; en NFS-e va en la discriminación del servicio. Elige un valor que tenga sentido en los tres contextos (ej: "Consultoría — Abril/2026", no "INV-2026-000123 fila-billing-interna").
payment_method
object
requerido
Cómo se recolectará el cobro.
payment_method.type
string
requerido
Uno de pix, boleto, bolepix, card (BR); card, ach_debit, bank_transfer (US — próximamente); card, sepa_debit, bank_transfer (UE — próximamente).
payment_method.expires_in_seconds
integer
Para pix / boleto / bolepix: tiempo de validez del artefacto. Por defecto 3600 (PIX) / 3 días (boleto).
payment_method.return_url
string
Para card: a dónde redirigir al cliente tras el checkout.
tax_document
object
Opcional. Cuando está presente, SalesOS emitirá un documento fiscal automáticamente tras el pago. Hoy solo BR.
tax_document.auto_issue
boolean
Cuando true, el documento fiscal se emite al transitar a paid. Cuando false (u omitido), usa POST /v1/invoices/{id}/tax-documents después.
tax_document.type
string
"nfse" (servicios BR — activo), "nfe" (productos BR — próximamente), "peppol" (UE — próximamente).
tax_document.service_code
string
Código municipal de servicio, obligatorio cuando type="nfse" (ej: "01.05" para consultoría en SP).
cost_center
string
requerido
Código de centro de costos interno (max 64 caracteres). Ver Campos de Control Comunes.
contractor_reference
string
Referencia del contratante — referencia externa del cliente/contrato (max 64 caracteres).
metadata
object
Pares clave-valor libres (max 50 claves, valor max 500 caracteres).
our_number (nuestro número) no va en el request — SalesOS lo genera al emitir y lo devuelve en el response (formato: INV-<AAAA>-<secuencia>). Almacénalo para conciliación.

GET /functions/v1/payments/invoices/{id} — consultar

curl -X GET https://api.play2sell.com/functions/v1/payments/invoices/inv_01HW1Z3K8C7G6Y9PQ4M5R2X0NA \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
La respuesta siempre incluye el artefacto actual de payment_method (QR PIX, código de barras de boleto, URL de checkout) y el resumen inline de tax_document cuando existe.

GET /functions/v1/payments/invoices — listar

Filtros: status (open|paid|canceled|failed), payment_method.type, cost_center, our_number, contractor_reference, created[gte], created[lte]. Paginación por cursor mediante limit (≤ 100), starting_after, ending_before.
curl -X GET "https://api.play2sell.com/functions/v1/payments/invoices?status=paid&cost_center=CC-OPERATIONS&limit=50" \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"

POST /functions/v1/payments/invoices/{id}/cancel — anular cobro no pagado

curl -X POST https://api.play2sell.com/functions/v1/payments/invoices/inv_01HW1Z3K8C7G6Y9PQ4M5R2X0NA/cancel \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Idempotency-Key: cancel-inv-001" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "customer_request" }'
Si la Invoice tiene un tax_document adjunto en estado issued, el cancelamiento se cascada al documento fiscal cuando el municipio aún está dentro de la ventana de cancelación. De lo contrario devuelve cancellation_window_expired.
El reembolso de cobros pagados no está expuesto en la v1. Si necesitas revertir un pago ya liquidado, contacta al soporte — el equipo puede procesarlo manualmente. Una versión futura de la API podría exponer un flujo de reembolso programático conforme los casos de uso maduren.

Tax Documents (Documentos Fiscales)

Un TaxDocument es el artefacto fiscal adjunto a una Invoice — hoy NFS-e (servicios BR). Tiene su propio ciclo de vida y puede emitirse, consultarse o cancelarse independientemente del cobro subyacente. Usa este recurso cuando optaste por no usar auto_issue al crear la Invoice, cuando un intento de auto-emisión falló y quieres reintentar, o cuando necesitas cancelar solo el documento fiscal.

POST /functions/v1/payments/invoices/{id}/tax-documents — emitir/reintentar

type
string
requerido
"nfse" hoy. Futuro: "nfe", "peppol".
service_code
string
Obligatorio cuando type="nfse".
metadata
object
Metadata libre opcional, persistida en el documento.
curl -X POST https://api.play2sell.com/functions/v1/payments/invoices/inv_01HW1Z3K8C7G6Y9PQ4M5R2X0NA/tax-documents \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Idempotency-Key: txd-2026-04-27-001" \
  -H "Content-Type: application/json" \
  -d '{ "type": "nfse", "service_code": "01.05" }'
Respuesta (202 Accepted):
{
  "id": "txd_01HW1Z3K8C7G6Y9PQ4M5R2X0NX",
  "invoice_id": "inv_01HW1Z3K8C7G6Y9PQ4M5R2X0NA",
  "type": "nfse",
  "status": "pending",
  "created": "2026-04-27T14:10:00Z"
}
La emisión es asíncrona. Escucha los webhooks tax_document.issued (o tax_document.failed). En éxito el documento trae document_number, xml_url, pdf_url e issued_at.

GET /functions/v1/payments/invoices/{id}/tax-documents/{doc_id} — consultar

POST /functions/v1/payments/invoices/{id}/tax-documents/{doc_id}/cancel — cancelar

curl -X POST "https://api.play2sell.com/functions/v1/payments/invoices/inv_.../tax-documents/txd_.../cancel" \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Idempotency-Key: cancel-txd-001" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "billing_correction" }'
Sujeto a la ventana de cancelación del municipio (típicamente el día de la emisión para NFS-e). cancellation_window_expired se devuelve fuera de la ventana.

Payouts (Pagos a Beneficiarios)

POST /functions/v1/payments/payouts — pagar a un beneficiario

Ruteo automático: currency = "BRL" → PIX cashout; otras monedas → transferencia internacional.
beneficiary
object
requerido
Destinatario del payout.
beneficiary.name
string
requerido
Nombre completo o razón social (max 255 caracteres).
beneficiary.document
string
requerido
Documento de identificación fiscal del beneficiario. CPF (11 dígitos) o CNPJ (14 dígitos) para BR; pasaporte o ID fiscal local para internacional. Obligatorio.
beneficiary.phone
string
requerido
Teléfono en formato E.164 (ej: "+5511999000111"). Obligatorio — usado para AML/KYC y notificaciones de estado del payout.
beneficiary.email
string
Email opcional. Cuando se provee, los recibos del payout se envían a esta dirección.
beneficiary.bank_account
object
requerido
Cuenta destino. Para PIX usa type: "pix" con key_type (cpf|cnpj|email|phone|evp) y key. Para internacional usa type: "bank_transfer" con country, iban o account_number + routing_number según los requisitos bancarios del país de destino.
amount
integer
requerido
Monto en unidades menores. Debe ser positivo.
currency
string
requerido
ISO-4217. Determina el ruteo de proveedor.
purpose
string
requerido
Uno de "prize", "commission", "vendor_payment", "other".
cost_center
string
requerido
Código de centro de costos (max 64 caracteres).
contractor_reference
string
Referencia del contratante — referencia externa (max 64 caracteres).
metadata
object
Pares clave-valor libres (max 50 claves, valor max 500 caracteres).
our_number (nuestro número) no va en el request — SalesOS lo genera al emitir y lo devuelve en el response (formato: PO-<AAAA>-<secuencia>). Almacénalo para conciliación.

GET /functions/v1/payments/payouts/{id} — consultar

GET /functions/v1/payments/payouts — listar

Filtros: status, provider, cost_center, our_number, contractor_reference, created[gte], created[lte]. Paginación por cursor.

POST /functions/v1/payments/payouts/{id}/cancel — cancelar

Disponible solo para transferencias internacionales en estado created / incoming_payment_waiting. PIX es síncrono y final — una vez aceptado no se cancela; emite un payout en sentido opuesto como reverso.

Balance Transactions (Extracto Bancario)

Libro mayor unificado entre proveedores. Solo lectura.

GET /functions/v1/payments/balance-transactions — listar

Filtros:
FiltroValores
accountomie, rinne, wise
typecharge, payout, fee, adjustment
cost_centercualquier string
our_numbercualquier string
contractor_referencecualquier string
currencycódigo ISO-4217
created[gte] / created[lte]timestamps ISO-8601
curl -X GET "https://api.play2sell.com/functions/v1/payments/balance-transactions?type=payout&created[gte]=2026-04-01&limit=100" \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"

GET /functions/v1/payments/balance-transactions/{id} — consultar

Cada movimiento expone:
id
string
ID estable del movimiento (btxn_...).
type
string
charge | payout | fee | adjustment.
amount
integer
Monto en unidades menores con signo. Negativo = salida, positivo = entrada.
currency
string
ISO-4217.
net
integer
amount - fee para salidas; amount para entradas.
fee
integer
Comisión del proveedor en unidades menores, siempre positiva.
available_on
string
Fecha ISO-8601 de liquidación de los fondos.
created
string
Timestamp ISO-8601 del movimiento.
source
object
{ resource, id } — apunta a la factura/payout origen.
cost_center
string
Heredado del recurso de origen.
our_number
string
Heredado del recurso de origen.
contractor_reference
string
Heredado del recurso de origen.

Campos de Control Comunes

Toda Invoice, Payout y Balance Transaction lleva los mismos campos de control. Hacen round-trip en GET y son filtrables en LIST.
CampoDirecciónFormatoMaxIndexadoUso
cost_centerinput (obligatorio)string, FK a tu tabla de centros de costo64Clasifica cada transacción contra una línea de presupuesto.
contractor_referenceinput (opcional)string64Referencia del contratante — referencia externa cliente/contrato (PO, ID de contrato, ID de evento).
metadatainput (opcional)Record<string, string>50 claves, valor 500 caracteresnoLibre. Usar con moderación; no indexable.
our_numbersolo outputstring, formato <PREFIJO>-<AAAA>-<secuencia>64Nuestro número — generado por SalesOS al emitir y devuelto en el response. Distinto de id (ULID para uso en la API). Estable, secuencial por tipo de recurso por tenant. Úsalo como clave de conciliación del lado bancario.
Por qué our_number lo genera el servidor. En el banking brasileño el cedente asigna el “nuestro número” — pero en esta API SalesOS es el gateway de emisión, así que SalesOS asigna el valor y lo devuelve. Si necesitas llevar tu identificador interno, usa contractor_reference (top-level, indexado) o metadata.* (libre).

Idempotencia

Todos los endpoints POST requieren el header Idempotency-Key — una cadena única a tu elección (max 255 caracteres; recomendamos UUIDv4 o una clave determinística derivada de tu dominio).
  • La primera llamada con la clave procesa normalmente y la respuesta se almacena por 24 h.
  • Reintentos con la misma clave y el mismo body devuelven la misma respuesta, con el header Idempotent-Replay: true.
  • Reintentos con la misma clave pero body distinto devuelven 409 idempotency_key_reused.
# Primera llamada — procesa
curl -X POST https://api.play2sell.com/functions/v1/payments/invoices \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Idempotency-Key: inv-2026-04-27-001" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 12345, "currency": "BRL", "payment_method": { "type": "pix" }, "...": "..." }'

# Segunda llamada (reintento de red) — misma respuesta, sin duplicación
curl -X POST https://api.play2sell.com/functions/v1/payments/invoices \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Idempotency-Key: inv-2026-04-27-001" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 12345, "currency": "BRL", "payment_method": { "type": "pix" }, "...": "..." }'

Montos y Moneda

Los montos son enteros en unidades menores para evitar errores de punto flotante:
MonedaUnidad menor12345 significa
BRLcentavoR$ 123,45
USDcentUS$ 123.45
EURcent€123,45
Las monedas siguen ISO-4217 (3 letras mayúsculas). Siempre acompaña amount con currency. Rechaza en el servidor cualquier payload que mezcle escalas (ej: enviar decimales).

Manejo de Errores

Todos los errores siguen RFC 9457 Problem Details:
{
  "type": "https://docs.play2sell.com/errors/validation_error",
  "title": "Invalid request",
  "status": 422,
  "detail": "amount must be a positive integer",
  "instance": "req_01HW1Z3K8C7G6Y9PQ4M5R2X0NA",
  "code": "validation_error",
  "errors": [
    { "field": "amount", "message": "must be a positive integer" }
  ]
}
JSON malformado o headers obligatorios ausentes. Corrige la solicitud y reenvía.
API key faltante, inválida o expirada. Verifica el header Authorization. Genera una clave nueva si expiró.
Clave válida pero sin el scope requerido (payments:write o payments:read). Edita la clave en el Dashboard.
El ID del recurso no existe o pertenece a otro tenant.
Misma Idempotency-Key usada con body distinto. Usa una clave nueva o reenvía el body original.
Validación del body falló. El array errors[] lista los problemas a nivel de campo.
Demasiadas solicitudes. El header Retry-After indica los segundos a esperar.
El backend downstream devolvió error. El campo detail contiene un mensaje sanitizado. Reenvía con la misma Idempotency-Key.
Error interno. Reenvía con backoff exponencial (2s, 4s, 8s). Contacta al soporte si persiste.

Webhooks

Configura un endpoint de webhook por entorno en Admin > Integraciones > Webhooks. SalesOS hará POST con JSON firmado para cada evento terminal:
EventoRecursoDisparado cuando
invoice.paidinvoiceCobro confirmado pagado por el proveedor
invoice.canceledinvoiceCobro no pagado anulado
invoice.failedinvoiceCobro falló definitivamente (ej: tarjeta rechazada, boleto expirado)
tax_document.issuedtax_documentDocumento fiscal aceptado por el municipio
tax_document.canceledtax_documentCancelamiento del documento fiscal aceptado
tax_document.failedtax_documentEmisión falló definitivamente
payout.paidpayoutFondos confirmados como entregados
payout.failedpayoutProveedor rechazó la transferencia
payout.canceledpayoutCancelamiento aceptado (solo transferencias internacionales)
Cada solicitud incluye:
  • X-Pay-Event — tipo del evento (ej: payout.paid).
  • X-Pay-Signaturet=<unix>,v1=<hex-hmac-sha256>. Verifica con el secreto configurado en el Dashboard.
  • X-Pay-Delivery — ID único de entrega, útil para deduplicación.
Verificación de firma (Node.js):
import crypto from 'node:crypto';

function verifyWebhook(rawBody, signatureHeader, secret) {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map(kv => kv.split('=')),
  );
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest('hex');
  const ok = crypto.timingSafeEqual(
    Buffer.from(parts.v1, 'hex'),
    Buffer.from(expected, 'hex'),
  );
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300; // 5 min
  return ok && fresh;
}
Payload de ejemplo:
{
  "id": "evt_01HW1Z9P7B5F2X8KQ4M5R2X0ND",
  "type": "payout.paid",
  "created": "2026-04-27T14:05:30Z",
  "data": {
    "id": "po_01HW1Z9P7B5F2X8KQ4M5R2X0NB",
    "status": "paid",
    "amount": 50000,
    "currency": "BRL",
    "cost_center": "CC-AWARDS",
    "our_number": "PO-2026-000045",
    "contractor_reference": "EVENT-Q2-WINNER-12"
  }
}

Ejemplos Completos de Código

export SALESOS_KEY="sk_live_YOUR_API_KEY"
export SALESOS_URL="https://api.play2sell.com/functions/v1/payments"

# 1. Issue an invoice (BR PIX charge with auto NFS-e)
curl -s -X POST "$SALESOS_URL/invoices" \
  -H "Authorization: Bearer $SALESOS_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": { "country": "BR", "tax_id": "12345678000190", "name": "Acme Corp", "email": "billing@acme.com" },
    "amount": 12345, "currency": "BRL",
    "description": "Consulting — April/2026",
    "payment_method": { "type": "pix", "expires_in_seconds": 3600 },
    "tax_document": { "auto_issue": true, "type": "nfse", "service_code": "01.05" },
    "cost_center": "CC-OPERATIONS", "contractor_reference": "PO-9981"
  }' | jq .

# 2. Pay a prize via PIX
curl -s -X POST "$SALESOS_URL/payouts" \
  -H "Authorization: Bearer $SALESOS_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "beneficiary": {
      "name": "Maria Santos", "document": "12345678901", "phone": "+5511999000111", "email": "maria@example.com",
      "bank_account": { "type": "pix", "key_type": "cpf", "key": "12345678901" }
    },
    "amount": 50000, "currency": "BRL", "purpose": "prize",
    "cost_center": "CC-AWARDS", "contractor_reference": "EVENT-Q2-WINNER-12"
  }' | jq .

# 3. Read the statement for the cost center
curl -s -X GET "$SALESOS_URL/balance-transactions?cost_center=CC-AWARDS&created[gte]=2026-04-01&limit=100" \
  -H "Authorization: Bearer $SALESOS_KEY" | jq .

Mejores Prácticas

Higiene de centros de costos

Elige un conjunto pequeño y estable de códigos (≤ 50). Documéntalos en el wiki de finanzas. Rechaza en el servidor llamadas que referencien códigos desconocidos — fallar ruidosamente es mejor que clasificar mal en silencio.

Usa ambas claves juntas para conciliación

  • our_number (generado por el servidor) es tu clave bancaria — impreso en el boleto / enviado al proveedor, presente en tu archivo de extracto bancario.
  • contractor_reference (lo proporcionas) es tu clave de contrato — el PO, ID de contrato con vendor o ID del evento referente; presente en tu ERP.
Cruzar ambas en el cierre mensual te da una conciliación de un clic entre el banco, la API Payments de SalesOS y tu ERP.

Ruteo por región

SalesOS rutea automáticamente por customer.country y currency. No necesitas escoger backend; confía en el ruteo.

Confiabilidad de webhooks

Trata los webhooks como fuente de verdad para estados terminales. El polling funciona pero consume rate limit. Verifica siempre X-Pay-Signature y deduplica por X-Pay-Delivery.

Manejo de fallos

  • 422: corrige los datos y reenvía con Idempotency-Key nueva.
  • 429: espera según Retry-After.
  • 502 (provider_error): reenvía con la misma Idempotency-Key — la solicitud original no hizo commit, así que reintentar es seguro.
  • 5xx: backoff exponencial (2s, 4s, 8s). Contacta al soporte si persiste.

Límites de Solicitudes

Cada API key tiene un límite configurable (por defecto: 1000 solicitudes por hora). El contador se reinicia cada hora.
LímiteValor
Solicitudes por hora (por defecto)1000
Tamaño máximo del payload1 MB
Tamaño máximo de página en listas100
Timeout por solicitud60 segundos
Las respuestas con rate limit incluyen el header Retry-After (segundos).

Seguridad

  • Las API keys se hashean con bcrypt — nunca se almacenan en texto plano.
  • Cada clave está limitada a un único tenant — sin acceso entre tenants.
  • Se pueden configurar listas de IPs permitidas por clave.
  • Todas las solicitudes se registran con fines de auditoría (inmutable, retención de 7 años).
  • Las claves pueden revocarse instantáneamente desde el Dashboard.
Nunca expongas tu API key en código del lado del cliente (JavaScript en el navegador, apps móviles o repositorios públicos). La API Payments solo debe ser llamada desde tu servidor backend.

Próximos Pasos

Autenticación

Aprende a crear y administrar API Keys

Integración Activities

Envía actividades de CRM a SalesOS

Soporte

¿Necesitas ayuda? Contacta a nuestro equipo de soporte