Sitios

Un sitio es un punto de venta del comercio: una tienda en línea, un canal telefónico, un punto físico. Cada sitio tiene sus propias credenciales, su moneda, su idioma y su configuración de operación.

La colección sites viaja en la raíz del cuerpo, junto a los campos del propio comercio, y la aceptan tanto la creación como la actualización. Una petición puede traer varios sitios a la vez.

Crear o modificar un sitio

Lo que determina si un elemento crea un sitio nuevo o modifica uno existente es la presencia del campo id:

El elemento
Efecto
Sin id
Crea un sitio nuevo. Todos los campos que describen un sitio pasan a ser obligatorios
Con id
Modifica ese sitio. Solo cambia lo que nombras; el resto se conserva

En una creación (POST), enviar sites[].id responde 422, porque no hay sitios previos que modificar. En una actualización, el id debe pertenecer al comercio de la URL. El campo customerId responde 422 siempre: el comercio viaja en la URL.

Credenciales del sitio

Cada sitio tiene sus propias credenciales, con las que se identifica ante la plataforma de pagos:

  • Name
    login
    Type
    string
    is optional
    Description

    Identificador público del sitio. Es único en todo el registro y no distingue mayúsculas de minúsculas.

  • Name
    tranKey
    Type
    string
    is optional
    Description

    Clave secreta del sitio.

Si no las envías, Onboarding las genera. Esa es la razón por la que son opcionales incluso al crear un sitio.

Como el login no distingue mayúsculas, ACME y acme son el mismo identificador y no pueden coexistir. Sigue estando disponible en dos casos, además de cuando está libre: cuando lo tiene el propio sitio que estás modificando, y cuando pertenece a un sitio que esta misma clave de idempotencia ya creó —sin lo cual un reintento colisionaría con su propio primer intento—.

Campos del sitio

  • Name
    name
    Type
    string
    is Required
    REQUERIDO
    Description

    Nombre interno del sitio.

  • Name
    displayName
    Type
    string
    is Required
    REQUERIDO
    Description

    Nombre que ve el comprador durante el pago.

  • Name
    type
    Type
    string
    is Required
    REQUERIDO
    Description

    Canal del sitio: INT (internet), POS (punto de venta), IVR (telefónico), REC (recurrente), ONE (pago único) o POS_AIR (punto de venta de aerolínea).

  • Name
    category
    Type
    string
    is Required
    REQUERIDO
    Description

    Categoría de operación del sitio.

  • Name
    email
    Type
    string
    is Required
    REQUERIDO
    Description

    Correo de contacto operativo del sitio.

  • Name
    currency
    Type
    string
    is Required
    REQUERIDO
    Description

    Moneda con la que opera, del catálogo de monedas.

  • Name
    language
    Type
    string
    is Required
    REQUERIDO
    Description

    Idioma del sitio, del catálogo de idiomas.

  • Name
    onTest
    Type
    boolean
    is optional
    Description

    Si el sitio opera en modo de pruebas.

  • Name
    active
    Type
    boolean
    is optional
    Description

    Si el sitio está habilitado.

A estos se suman siete bloques de configuración, descritos abajo.

sites

{
  "sites": [
    {
      "name": "Tienda principal",
      "displayName": "Acme",
      "type": "INT",
      "category": "ECOMMERCE",
      "email": "[email protected]",
      "currency": "COP",
      "language": "ES",
      "onTest": true,
      "integration": {
        "allowPartial": false,
        "checkoutVersion": "v4",
        "connectionMethod": "REDIRECT",
        "notificationUrl": "https://acme.example.com/pay/notify",
        "allowWallet": true,
        "checkoutAttemptsLimit": 5
      },
      "control": {
        "minAmount": 1000,
        "maxAmount": 5000000,
        "allowedDays": 127,
        "allowedHours": "ffffffffffffffffffffffffffffffffffffffffff",
        "filterPse": false,
        "filterByBin": false,
        "allowedBankCountries": ["CO"]
      },
      "threeDS": { "setting": "LOW", "minAmount": 0 },
      "securityFilters": { "onlyWhitelisted": false, "dayMax": 5 },
      "operation": { "taxPercentage": 19, "mailCustomer": true },
      "branding": { "buttonColor": "#1a73e8" }
    }
  ]
}

Bloque integration

Define cómo se conecta el sitio con la plataforma de pagos.

  • Name
    integration.checkoutVersion
    Type
    string
    is optional
    Description

    Versión de la página de pago. Actualmente solo se admite v4.

  • Name
    integration.connectionMethod
    Type
    string
    is optional
    Description

    Modo de conexión, por ejemplo REDIRECT.

  • Name
    integration.notificationUrl
    Type
    string
    is optional
    Description

    URL donde el sitio recibe las notificaciones de sus transacciones.

  • Name
    integration.checkoutAttemptsLimit
    Type
    integer
    is optional
    Description

    Número de intentos de pago permitidos por sesión. Solo admite los valores que ofrece la configuración estándar.

  • Name
    integration.allowPartial
    Type
    boolean
    is optional
    Description

    Si se admiten pagos parciales.

  • Name
    integration.allowWallet
    Type
    boolean
    is optional
    Description

    Si se admite el uso de billetera.

  • Name
    integration.allowConfirmationFlow
    Type
    boolean
    is optional
    Description

    Si el sitio admite el flujo de confirmación manual: con true, un pago creado con requiresConfirmation queda a la espera de que el comercio lo confirme o lo cancele antes de autorizarse. Ver Sesiones con confirmación. Un sitio creado sin esta clave se lee como false, y la clave no admite null: para desactivarlo, envía false.

Bloque control

Restringe cuándo y con qué montos puede operar el sitio.

  • Name
    control.minAmount
    Type
    number
    is optional
    Description

    Monto mínimo admitido por transacción.

  • Name
    control.maxAmount
    Type
    number
    is optional
    Description

    Monto máximo admitido por transacción.

  • Name
    control.allowedDays
    Type
    integer
    is optional
    Description

    Días de la semana habilitados, como máscara de bits. El valor 127 los habilita todos; el valor 0 responde 422, porque dejaría el sitio sin ningún día operativo.

  • Name
    control.allowedHours
    Type
    string
    is optional
    Description

    Horas habilitadas, codificadas como una cadena hexadecimal.

  • Name
    control.allowedBankCountries
    Type
    array
    is optional
    Description

    Países cuyos bancos se admiten.

  • Name
    control.filterPse
    Type
    boolean
    is optional
    Description

    Si se aplica filtrado sobre pagos bancarios.

  • Name
    control.filterByBin
    Type
    boolean
    is optional
    Description

    Si se filtra por BIN de tarjeta.

  • Name
    control.exceptionBinsList
    Type
    array
    is optional
    Description

    BINes exceptuados del filtro.

Los demás bloques

Bloque
Para qué
threeDS
Configuración de autenticación 3-D Secure: nivel de exigencia y monto a partir del cual se aplica. Al crear el comercio admite además seglan, que registra el sitio en Seglan. Ver la referencia de la API
securityFilters
Límites antifraude por número de intentos y de tarjetas, por día, semana y mes
operation
Parámetros operativos: porcentaje de impuesto, correos al comprador, comprobantes
subscriptionValidation
Configuración de la validación al registrar un medio de pago
branding
Colores e imagen de la página de pago. Los colores se envían como #rgb o #rrggbb

Varios límites son más estrechos que lo que el registro admitiría, porque replican los que impone la configuración estándar de la plataforma. Enviar un valor fuera de esos límites responde 422 señalando el campo.

Metadatos del sitio

El bloque metadata guarda información propia del comercio, destinada a un proceso pactado con Placetopay aparte de este contrato. Es opcional y lo aceptan tanto la creación como la actualización.

Es el único bloque de un sitio sin vocabulario cerrado: los nombres los eliges tú, no el catálogo. La excepción es copper, un nombre reservado para los sitios migrados desde Copper, con reglas propias.

El valor de un nombre puede ser un dato simple —un texto, un número, un booleano— o una estructura: un objeto o una lista. Un dato simple conserva el tipo con el que lo envías: un número sigue siendo número y un booleano, booleano.

metadata

{
  "sites": [
    {
      "name": "Tienda principal",
      "metadata": {
        "contractRef": "AC-2026-0042",
        "onboardingBatch": 17,
        "requiresManualReview": true,
        "reviewers": ["riesgo", "legal"]
      }
    }
  ]
}

Qué admite un nombre y qué admite un valor

Un nombre admite hasta 64 caracteres y distingue mayúsculas.

Un valor es un dato simple o una estructura. El anidamiento llega hasta tres niveles, y cada dato simple admite 1024 caracteres, esté suelto o dentro de una estructura.

Se fusiona, y se borra nombrando la clave

El documento se fusiona: una clave que el cuerpo no nombra sobrevive con el valor que ya tenía.

Para retirar una clave, nómbrala con null o con la cadena vacía. Es la misma instrucción que ya usan los settings de un medio de pago. En una creación ambas se rechazan, porque no hay nada que borrar.

No existe forma de vaciar el documento entero de una vez: "metadata": null responde 422. Se borra clave por clave.

La fusión ocurre por nombre de primer nivel, y el valor se reemplaza entero: reenviar un objeto no lo combina con el que estaba guardado. Para retirar una entrada de un objeto guardado, reenvía el objeto entero sin ella.

Retirar una clave

{
  "sites": [
    {
      "id": 412,
      "metadata": {
        "onboardingBatch": 18,
        "reviewedBy": "riesgo",
        "legacyFlag": null
      }
    }
  ]
}

contractRef sobrevive sin haberse reenviado, legacyFlag desaparece por haberse nombrado con null, y las otras dos se escriben.

El tamaño se mide sobre el documento resultante

Es una consecuencia directa de la fusión: como el documento nunca se reemplaza, solo puede crecer. Acotar únicamente la petición dejaría pasar escrituras que después no se podrían almacenar.

Retirar claves es la única forma de recuperar espacio. Si un sitio se acerca al tope, nombra con null lo que ya no uses.

Ten en cuenta también que el bloque se valida en cadena y se detiene en el primer fallo: si envías a la vez un nombre inválido y un documento demasiado grande, solo verás el error del nombre.

Los límites exactos están en la referencia de la API, junto con la longitud máxima de un nombre y de un valor.

Dónde se lee

Un cuerpo que no envía metadata deja el result exactamente igual que antes de que este bloque existiera.

El back office todavía no muestra estos datos. Quedan guardados y auditados, pero verlos desde la ficha del sitio requiere un desarrollo pendiente del lado del back office.

Sitios migrados desde Copper

Un sitio que llega desde Copper se marca con el nombre reservado copper dentro de metadata, que guarda los datos de su integración de origen. Con is_migrated: true, el sitio queda migrado.

copper es el único nombre de metadata con vocabulario cerrado: diez claves, cada una con su tipo. Los demás nombres siguen siendo libres, y un sitio que no es migrado no necesita enviarlo.

Las claves se guardan y se devuelven tal como llegaron. La API valida su forma, pero no cambian cómo procesa Placetopay los pagos del sitio: requires_cvv: true, por ejemplo, no hace que se pida el código de seguridad.

Un sitio migrado

{
  "sites": [
    {
      "name": "Tienda principal",
      "metadata": {
        "copper": {
          "is_migrated": true,
          "id": "cu_8f2a91",
          "parent_id": "cu_1d77e0",
          "integration_type": "TC",
          "secret": "exampleCopperSecret",
          "error_code_level": 2,
          "card_data_return": "bin_last4",
          "allow_preauth": false,
          "requires_cvv": true,
          "assigned_version": "1.0"
        }
      }
    }
  ]
}

Las diez claves

Clave
Tipo
Obligatoria con is_migrated: true
Valores admitidos
is_migrated
booleano
Es la marca
true, false
id
texto
Sí
Cualquier texto
integration_type
texto
Sí
TC (Transacción Completa) o WP (Webpay)
error_code_level
entero
Sí
Del 0 al 9
allow_preauth
booleano
Sí
true, false
requires_cvv
booleano
Sí
true, false
assigned_version
texto
Sí
1.0, 1.1, 1.2, 1.3
parent_id
texto
No
Cualquier texto
secret
texto
No
Cualquier texto
card_data_return
texto
No
none, last4, bin_last4, bin_only

id es el identificador del sitio en Copper, y parent_id, el identificador en Copper del comercio padre. secret es el secreto de la integración en Copper, y assigned_version, la versión de la integración que Copper le asignó al sitio.

Cómo se valida

  • Solo is_migrated: true marca el sitio como migrado, y entonces exige las seis claves obligatorias. Con false, o sin la clave, no se exige ninguna, pero las que envíes se validan igual: tipo y valores admitidos.
  • Los tipos son estrictos. Un booleano es true o false de JSON: "true", "1" y 1 responden 422. Un entero es un número de JSON: "2" responde 422. Una versión es una cadena de JSON con uno de los cuatro valores exactos: 1.1 como número, "1" y "1.10" responden 422.
  • Ninguna clave admite null ni texto vacío, tampoco is_migrated. Una clave sin valor simplemente no se envía.
  • copper es un objeto con al menos una clave. {}, una lista o un valor suelto responden 422.
  • Una clave fuera de las diez responde 422, y el error la nombra. Así, una errata como is_migrate no deja el sitio sin marcar en silencio.
  • El id de Copper no tiene que ser único: dos sitios pueden compartirlo, en la misma petición o en comercios distintos.
  • Siguen rigiendo los límites de metadata: 1024 caracteres por texto, tres niveles de anidamiento y el tope de tamaño del documento.

En una actualización

copper se reemplaza entero, como cualquier valor de primer nivel de metadata: las claves que no reenvíes desaparecen. Por eso las obligatorias se exigen sobre lo que envías y no sobre lo guardado, y para cambiar una sola clave de un sitio migrado hay que reenviar el bloque completo.

Para que un sitio deje de ser migrado, envía "copper": null o la cadena vacía, como con cualquier nombre de metadata: el bloque desaparece y los demás nombres no se tocan. También deja de serlo si reenvías el bloque con "is_migrated": false.

En una creación, tanto null como la cadena vacía responden 422, igual que en el resto de metadata.

Quitar la marca

{
  "sites": [
    {
      "id": 214,
      "metadata": {
        "copper": null
      }
    }
  ]
}

Los errores

Cada problema llega en errors bajo la ruta de la clave, como cualquier otro error de validación. Estos son los mensajes propios del bloque, tomando como ejemplo el primer sitio del cuerpo:

Qué ocurre
Mensaje
Falta una clave obligatoria con is_migrated: true
The sites.0.metadata.copper.id field is required when sites.0.metadata.copper.is_migrated is true.
Una clave fuera de las diez
The sites.0.metadata.copper field contains keys that are not part of this contract: is_migrate.
Un booleano que no es true ni false
The sites.0.metadata.copper.requires_cvv field must be true or false.
Un entero que no es un número de JSON
The sites.0.metadata.copper.error_code_level field must be an integer.
Un texto que no es una cadena
The sites.0.metadata.copper.id field must be a string.
Una clave con null o texto vacío
The sites.0.metadata.copper.secret field must have a value.
Un valor fuera de los admitidos
The selected sites.0.metadata.copper.integration_type is invalid.
error_code_level fuera de rango
The sites.0.metadata.copper.error_code_level field must be between 0 and 9.
"copper": {} en una actualización
The sites.0.metadata.copper field must have at least 1 items.

Comportamiento en una actualización

La colección es upsert-only: un sitio que el cuerpo no nombra sobrevive intacto, y dentro de un sitio que sí nombras solo cambia lo que envías.

Los bloques branding y los ajustes internos del sitio se fusionan en lugar de reemplazarse, porque contienen claves que solo la plataforma escribe y que una actualización no podría restaurar.

Efectos de una edición posterior desde el back office

Hay tres valores que la plataforma normaliza la primera vez que una persona guarda el sitio desde el back office. No son fallos y no se pueden devolver como error, pero conviene conocerlos:

  • Un allowedHours que no habilite ninguna hora se convierte en «todas las horas».
  • Una fecha de expiración pierde su componente de hora.
  • Una comisión heredada de un medio de pago del sitio pasa a 0.00. Ver Medios de pago del sitio.

El resultado

  • Name
    id
    Type
    integer
    is Required
    REQUERIDO
    Description

    Identificador del sitio. Es el que usarás para modificarlo después.

  • Name
    login
    Type
    string
    is Required
    REQUERIDO
    Description

    Identificador público del sitio.

  • Name
    tranKey
    Type
    string
    is Required
    REQUERIDO
    Description

    Clave secreta. La clave siempre viaja; su valor es null si esta petición no la escribió.

  • Name
    active
    Type
    boolean
    is Required
    REQUERIDO
    Description

    Estado del sitio tras la operación.

  • Name
    action
    Type
    string
    is Required
    REQUERIDO
    Description

    created, updated o unchanged. Un sitio se reporta como unchanged cuando ninguno de sus campos difiere de lo almacenado, de modo que reenviar el mismo cuerpo no lo marca como editado.

La clave tranKey está siempre presente; lo que cambia es su valor, que solo llega si esta misma petición la escribió: porque la enviaste, o porque se generó al crear el sitio.

En un alta nunca es null, porque si no envías las credenciales se generan. El null aparece cuando un elemento solo modificó un sitio existente: ahí no hay nada irrecuperable que rescatar, solo un secreto que nunca enviaste.

Más concretamente, en una actualización el valor vuelve solo si cambió. Reenviar el mismo tranKey que ya está guardado devuelve null, porque no hay ningún cambio que reportar — algo que sorprende si tu sistema envía el cuerpo completo en cada actualización y espera recuperar ahí la credencial.

Si pierdes las credenciales

Puedes volver a leerlas con Consultar un comercio, que devuelve las credenciales de cada sitio en claro.

Si lo que necesitas es reemplazarlas —porque quedaron expuestas, por ejemplo—, fija unas nuevas. Envía un tranKey distinto en una actualización del sitio: al cambiar de valor se escribe, y viaja en el result de ese proceso.

result

{
  "result": {
    "merchantId": 18,
    "sites": [
      {
        "id": 214,
        "login": "aabbccdd1234567890aabbccdd123456",
        "tranKey": "exampleTranKey16",
        "md5Hash": "exampleMd5Hash16",
        "active": true,
        "action": "created"
      },
      {
        "id": 209,
        "login": "example456token789abc012def3456",
        "tranKey": null,
        "md5Hash": null,
        "active": true,
        "action": "updated"
      }
    ]
  }
}

Las claves se mantienen siempre presentes para que la forma del resultado no dependa de qué cambió.

Colecciones dentro de un sitio

Un sitio puede llevar sus propias colecciones, con reglas propias:

¿Qué sigue?