Crear un comercio

POST /api/merchants registra un comercio nuevo. La petición no espera a que el comercio quede escrito: valida el contenido, lo acepta y devuelve un identificador de proceso con el que seguir el resultado.

La petición

Solicitud

POST
/api/merchants
curl --request POST \
  --url '{URL_BASE}/api/merchants' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer {TU_TOKEN}' \
  --header 'Idempotency-Key: 8f1c2d3e4a5b6c7d8e9f0a1b' \
  --data @merchant.json
Header
Obligatorio
Detalle
Authorization
Bearer con un token que incluya el permiso onboarding:create. Ver Autenticación
Idempotency-Key
Content-Type
application/json
Accept
Recomendado
application/json

Estructura del cuerpo

El cuerpo describe el estado completo del comercio que quieres registrar. Los campos del comercio viajan en la raíz, al lado de las colecciones.

  • Name
    Campos del comercio
    Type
    varios
    is Required
    REQUERIDO
    Description

    Identidad, documento, dirección, representante legal, facturación y control comercial. Van directamente en la raíz: name, brand, document, address… Ver Datos del comercio.

  • Name
    integrations
    Type
    array
    is optional
    Description

    Integraciones del comercio con proveedores externos. Ver Integraciones.

  • Name
    paymentMethods
    Type
    array
    is optional
    Description

    Medios de pago que el comercio acepta. Ver Medios de pago.

  • Name
    sites
    Type
    array
    is optional
    Description

    Sitios de venta del comercio, con sus propias integraciones y medios de pago. Ver Sitios.

  • Name
    notification
    Type
    object
    is optional
    Description

    URL donde quieres recibir el resultado del proceso.

Cuerpo mínimo

Estos son todos los campos que Onboarding exige para registrar un comercio. Todo lo demás es opcional.

Cuerpo mínimo

{
  "name": "Comercializadora Acme S.A.S.",
  "brand": "Acme",
  "languages": ["es"],
  "currencies": ["COP"],
  "document": {
    "type": "NIT",
    "number": "9001234567"
  },
  "address": {
    "city": "Bogota",
    "country": "CO",
    "state": 11
  },
  "legalRepresentative": {
    "name": "Ada",
    "surname": "Lovelace"
  },
  "control": {
    "reseller": 1
  }
}

Cuerpo completo

Un registro real suele incluir también las colecciones. Este ejemplo muestra la forma general; el detalle de cada colección está en su propia página.

Los campos del comercio y las colecciones conviven en el mismo nivel del cuerpo.

Las colecciones son independientes entre sí: puedes enviar solo sites, solo paymentMethods, ambas o ninguna. Cada elemento que envías se registra dentro de la misma operación, de modo que un comercio con sus sitios y sus medios de pago se crea con una sola petición.

El bloque notification es opcional y se explica más abajo.

Cuerpo completo

{
  "name": "Comercializadora Acme S.A.S.",
  "brand": "Acme",
  "active": true,
  "url": "https://acme.example.com",
  "mcc": "5411",
  "size": "M",
  "timezone": "America/Bogota",
  "languages": ["es", "en"],
  "currencies": ["COP", "USD"],
  "document": {
    "type": "NIT",
    "number": "9001234567"
  },
  "address": {
    "street": "Carrera 43A # 1-50, Torre 2",
    "city": "Bogota",
    "country": "CO",
    "state": 11,
    "phone": "6013905000",
    "postalCode": "110111"
  },
  "legalRepresentative": {
    "name": "Ada",
    "surname": "Lovelace",
    "documentType": "CC",
    "document": "1020304050"
  },
  "billing": {
    "contact": "Contabilidad Acme",
    "mail": "[email protected]",
    "ciiu": "4791",
    "taxType": 1,
    "taxRegime": 1,
    "organizationType": 1
  },
  "control": {
    "reseller": 1,
    "seller": 1
  },
  "integrations": [
    {
      "type": "kount",
      "settings": {
        "sandbox": false,
        "website": "ACME",
        "merchant": "201000"
      }
    }
  ],
  "paymentMethods": [
    {
      "code": "CR_VS",
      "financialEntity": 7,
      "accountNumber": "1234567890",
      "accountType": 2,
      "commissionModel": "P",
      "commissionValue": 2.5
    }
  ],
  "notification": {
    "url": "https://acme.example.com/hooks/onboarding"
  }
}

La URL de notificación

Si envías notification.url, Onboarding te avisará en esa dirección cuando el proceso termine, tanto si termina bien como si falla.

  • Name
    notification.url
    Type
    string
    is optional
    Description

    URL pública sobre https donde recibirás el webhook, sin credenciales embebidas.

Onboarding valida solo la forma de la URL en el momento de aceptar la petición. La accesibilidad real del destino se comprueba justo antes de cada envío, de modo que una URL que apunte a una red no pública se acepta pero nunca se entrega. El detalle está en Notificación.

La respuesta

Si el contenido es válido, la respuesta es 202.

  • Name
    status
    Type
    object
    is Required
    REQUERIDO
    Description

    Estado de la petición. En el 202 siempre es OK, y significa que la petición fue aceptada.

  • Name
    processId
    Type
    string
    is Required
    REQUERIDO
    Description

    Identificador del proceso. Consérvalo: es con lo que consultarás el resultado.

  • Name
    action
    Type
    string
    is Required
    REQUERIDO
    Description

    La operación pedida. En una creación, merchant.create.

Además, dos headers:

Header
Para qué
Location
URL del proceso recién creado
Retry-After
Segundos a esperar antes de consultar

Respuesta

{
  "status": {
    "status": "OK",
    "reason": null,
    "message": "The request was accepted and will be processed shortly.",
    "date": "2026-08-17T10:14:03-05:00"
  },
  "processId": "01kz0609xy2hd666mnx6b0jxpc",
  "action": "merchant.create",
  "result": null,
  "notification": {
    "url": "https://acme.example.com/hooks/onboarding",
    "state": "PENDING",
    "attempts": 0
  }
}

Qué hacer después

  1. Guarda el processId asociado a la operación en tu sistema.
  2. Consulta el proceso con GET /api/processes/{processId} hasta que la respuesta deje de traer Retry-After.
  3. Guarda result.merchantId cuando el proceso termine bien.

Si registraste una URL de notificación, puedes esperar el webhook en lugar de consultar — pero mantén la consulta como respaldo, porque la entrega no está garantizada.

Errores de la llamada

Estos errores impiden que la petición se acepte. Ninguno crea un proceso, y por eso ninguno trae processId.

Código
Causa
401
Token ausente, inválido o de otro ambiente
403
El token no incluye el permiso onboarding:create
409
La clave de idempotencia ya se usó con un contenido distinto
422
El contenido no pasó la validación, o falta el header Idempotency-Key

Un 422 incluye un objeto errors hermano de status, con una entrada por cada campo rechazado. Las claves son las rutas del propio cuerpo que enviaste, de modo que puedes localizar el problema sin traducir nada.

Respuesta de error

{
  "status": {
    "status": "FAILED",
    "reason": 422,
    "message": "The given data was invalid.",
    "date": "2026-08-17T10:14:03-05:00"
  },
  "errors": {
    "name": ["The name field is required."],
    "currencies.0": ["The selected currencies.0 is invalid."]
  }
}

La validación no se detiene en el primer error: la respuesta enumera todos los problemas encontrados, para que puedas corregirlos de una vez. El catálogo completo de errores está en Errores.

¿Qué sigue?