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:
sites[].id es la única excepción a la regla de que los identificadores no viajan en el cuerpo. Es necesaria porque un sitio no tiene otro campo estable con el que referenciarlo: su nombre de acceso puede cambiarlo la misma petición.
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.
Una credencial generada se publica una sola vez, en result.sites[] del proceso. No hay forma de recuperarla después. Guarda el resultado del proceso en cuanto lo recibas.
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) uONE(pago único).
- 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" }
}
]
}
La moneda y el idioma se validan contra el catálogo respetando la grafía exacta, igual que el código de un medio de pago.
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.
integration.notificationUrl puede ser sobrescrito por una integración de sitio de tipo notifier. Ver Integraciones del sitio.
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
127los habilita todos; el valor0responde422, 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
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. A cambio, la forma sí es fija — un valor por nombre. Un objeto o una lista bajo un nombre responden 422.
El valor 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
}
}
]
}
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.
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
El tope de tamaño no se aplica a lo que envías, sino al documento que quedaría guardado. Eso significa que una petición pequeña puede responder 422 por lo que el sitio ya tenía almacenado. El mensaje nombra los dos tamaños: el que resultaría y el máximo admitido.
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.
metadata cuenta además dentro del tamaño máximo del sitio, del que las colecciones integrations y paymentMethods sí están exentas. Un sitio corriente con un metadata en su tope cabe sin problema, pero en un sitio con muchos datos propios puede ser lo que lo empuje fuera del límite — y entonces el 422 señala el sitio entero, no el bloque. Si recibes ese error sobre un sitio que no has agrandado, mira su metadata.
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.
No se puede leer de vuelta
metadata no viaja en result, y por tanto tampoco en la notificación ni en GET /api/processes/{processId}. Tampoco hay ningún endpoint que lo devuelva. Conserva tu propia copia: esta API no te la puede restituir.
Un cuerpo que no envía metadata deja el result exactamente igual que antes de que este bloque existiera.
Qué no poner aquí
No es sitio para un secreto ni para un dato personal. El documento se guarda en claro, se copia entero al registro de auditoría del back office —cuya retención no controla esta API— y se conserva en el contenido del proceso, donde nada lo oculta.
Ten en cuenta además que 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.
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.
No se puede eliminar un sitio. Ni omitiéndolo ni enviando "sites": [], que responde 422. Para dejar un sitio fuera de operación, envíalo con active: false.
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
allowedHoursque 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
nullsi 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,updatedounchanged. Un sitio se reporta comounchangedcuando 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
No hay forma de volver a leerlas: ningún endpoint las devuelve. Lo que sí puedes hacer es fijar 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.
El valor anterior deja de estar almacenado, y Onboarding no lo conserva en ningún otro registro: en el historial de cambios las credenciales quedan enmascaradas, tanto la nueva como la que se reemplazó. Tampoco se emite ninguna notificación por el cambio.
Lo que esta documentación no describe es qué le ocurre a una integración que estuviera usando la credencial anterior. Eso lo determina el sistema que la valida al procesar un pago, no Onboarding, que se limita a escribir el nuevo valor.
result
{
"result": {
"merchantId": 18,
"sites": [
{
"id": 214,
"login": "aabbccdd1234567890aabbccdd123456",
"tranKey": "ABC123example456trankey+789abc012def3456ABC=",
"active": true,
"action": "created"
},
{
"id": 209,
"login": "123example456token789abc012def345",
"tranKey": 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:
- Integraciones del sitio —
sites[].integrations - Medios de pago del sitio —
sites[].paymentMethods