Documentación de la API

API para que el sistema de una empresa cliente registre solicitudes de compra en nombre de sus empleados.

URL base: https://tiendagem.com · Todo viaja en JSON (Content-Type: application/json).

No hay pasarela de pago. El empleado paga por descuento de nómina, que la empresa aplica por su lado. Por eso una solicitud nace en estado Requested y solo GEM la pasa a Sold.

1. Autenticación

GEM le entrega un clientId y un clientSecret. El secreto se muestra una sola vez: si se pierde, hay que regenerarlo. Con ellos se pide un token que dura 60 minutos y se envía en cada llamada.

POST /api/auth/token

{
  "clientId": "su-client-id",
  "clientSecret": "su-client-secret"
}

Respuesta 200:

{
  "accessToken": "eyJhbGciOi...",
  "tokenType": "Bearer",
  "expiresInSeconds": 3600,
  "expiresAt": "2026-08-14T15:30:00"
}

En las demás llamadas incluya la cabecera:

Authorization: Bearer <accessToken>
Un 401 en el token significa siempre lo mismo —credenciales inválidas o empresa inactiva— sin decir cuál de las dos. Si le ocurre de repente, es probable que GEM haya revocado el token o regenerado el secreto.
Su catálogo es el que GEM le asignó, no el catálogo completo. Solo verá los productos habilitados para su empresa; el resto no existe para usted. Si su catálogo aparece vacío, comuníquese con GEM: aún no hay productos asignados.

Los precios ya vienen con el descuento de su empresa aplicado. price es lo que paga el empleado; listPrice es el precio de lista y se incluye solo como referencia.

MétodoRutaDevuelve
GET/api/productsArreglo de productos
GET/api/products/{id}Un objeto, sin arreglo

GET /api/products → un arreglo, vacío ([]) si no hay nada asignado:

[
  {
    "id": 1,
    "name": "Gafas formuladas",
    "description": "Montura y lentes",
    "sku": "GAF-001",
    "listPrice": 150000.00,
    "discountPercentage": 10.00,
    "price": 135000.00,
    "imageUrl": "https://..."
  }
]

GET /api/products/1 → el objeto solo, no un arreglo de uno:

{
  "id": 1,
  "name": "Gafas formuladas",
  "description": "Montura y lentes",
  "sku": "GAF-001",
  "listPrice": 150000.00,
  "discountPercentage": 10.00,
  "price": 135000.00,
  "imageUrl": "https://..."
}

Si el producto no existe —o no está asignado a su empresa— la respuesta es 404 con el cuerpo de error, nunca un arreglo vacío.

imageUrl es un enlace temporal: genérelo de nuevo cuando lo necesite, no lo guarde.

3. Solicitudes

MétodoRutaQué hace
GET/api/salesArreglo de sus solicitudes
GET/api/sales/{id}Un objeto, sin arreglo
POST/api/salesRegistrar una compra
PUT/api/sales/{id}/cancelCancelar

POST /api/sales

{
  "employee": {
    "name": "Juan",
    "lastName": "Pérez",
    "documentNumber": 1020304050,
    "documentType": 0,
    "phone": "3001234567",
    "email": "juan.perez@empresa.com",
    "city": "Bogotá"
  },
  "lines": [
    { "productId": 1, "quantity": 2 }
  ],
  "externalReference": "SOL-001",
  "notes": "Opcional"
}

Respuesta 201 — un objeto. Es la misma forma que devuelven GET /api/sales/{id} y PUT /api/sales/{id}/cancel; GET /api/sales devuelve un arreglo de estos:

{
  "id": 15,
  "status": "Requested",
  "statusLabel": "Solicitado",
  "saleDate": "2026-08-14T10:22:00",
  "grossTotal": 300000.00,
  "discountPercentage": 10.00,
  "total": 270000.00,
  "phone": "3001234567",
  "email": "juan.perez@empresa.com",
  "city": "Bogotá",
  "externalReference": "SOL-001",
  "notes": null,
  "cancelledAt": null,
  "employee": { "id": 3, "name": "Juan", "lastName": "Pérez", "phone": "3001234567", ... },
  "lines": [
    { "productId": 1, "productName": "Gafas formuladas",
      "quantity": 2, "unitPrice": 150000.00, "subtotal": 300000.00 }
  ]
}

Cinco cosas que conviene saber

  • phone, email y city son opcionales, para no romper integraciones ya en marcha, pero envíelos: quedan guardados en la solicitud tal como llegaron y GEM los usa para contactar y entregar. Si los manda distintos a los de una compra anterior, se actualiza la ficha del empleado; si los omite, se conserva lo que ya había.
  • No hace falta registrar empleados. Se crean solos la primera vez que compra ese documento. Si el mismo documento vuelve, se reutiliza el registro, y así las compras quedan agrupadas por persona.
  • externalReference hace el POST idempotente. Si su sistema reintenta con la misma referencia, recibe la solicitud existente en vez de crear una segunda. Úselo siempre: es su seguro contra cobros duplicados.
  • El precio se congela al momento de registrar. Un cambio posterior en el catálogo, o en el descuento de su empresa, no altera lo ya solicitado.
  • Los valores los calcula GEM. Usted envía únicamente productId y quantity. La petición no acepta precios ni totales: si los envía, se ignoran. grossTotal es la suma a precio de lista, se le aplica discountPercentage y el resultado es total.

PUT /api/sales/{id}/cancel

Sin cuerpo. Solo funciona dentro del plazo acordado con su empresa y mientras la solicitud siga en Requested. Cancelar dos veces no da error.

4. Datos personales

Cada POST /api/sales transporta datos identificables de un empleado suyo. Esta sección dice qué hace GEM con ellos y qué se espera de usted, según la Ley 1581 de 2012.

Usted responde por la autorización. La relación laboral con el empleado es suya, no de GEM. Antes de enviarnos sus datos debe contar con su autorización previa, expresa e informada para este fin, y conservar la prueba. GEM registra la solicitud confiando en que usted ya la obtuvo.

Qué guarda GEM de cada solicitud

Nombres y apellidos, tipo y número de documento, la empresa a la que pertenece y el detalle de la compra. Nada más: no pedimos correo, teléfono, dirección ni cargo, y no hay pasarela de pago, así que por esta API no viaja ningún dato financiero.

Envíe lo mínimo

  • No use notes ni externalReference para datos personales. Son campos de texto libre pensados para su número de caso o una observación logística. Un correo, un teléfono o un diagnóstico ahí terminan almacenados sin necesidad y fuera de lo acordado.
  • No envíe datos sensibles. Ni fórmulas médicas, ni diagnósticos, ni historia clínica, ni datos biométricos o sindicales. La API no tiene dónde ponerlos y GEM no los quiere: son datos sensibles del artículo 5 de la Ley 1581 y exigen un régimen que esta integración no contempla.
  • Solo empleados mayores de edad. Aunque el catálogo de tipos de documento incluye la tarjeta de identidad, la tienda está dirigida a trabajadores adultos.
Auditoría. GEM conserva el cuerpo de cada POST como registro de auditoría de la integración, salvo el de /api/auth/token, que se excluye por contener el clientSecret. Téngalo presente al decidir qué incluye en la petición: es otra razón para no mandar de más.

Si un empleado ejerce sus derechos

Un empleado puede pedir conocer, actualizar, rectificar o suprimir sus datos. Si la petición le llega a usted y se refiere a lo que está en la tienda, remítala al canal de la política de tratamiento de GEM. Los plazos legales —10 días hábiles para una consulta, 15 para un reclamo— corren desde que la petición se recibe, así que no la deje reposar.

Seguridad de la integración

  • Llame siempre por https. Una petición en claro expone documentos de identidad.
  • Guarde el clientSecret en un almacén de secretos, nunca en el código fuente ni en un archivo de configuración versionado.
  • No reenvíe el accessToken al navegador del empleado ni a sistemas de terceros: identifica a su empresa entera, no a una persona.
  • Si sospecha que el secreto se filtró, pida a GEM regenerarlo. Eso revoca de inmediato todos los tokens emitidos con el anterior.

Tipos de documento

ValorSignificado
0Cédula de ciudadanía
1Tarjeta de identidad
2Cédula de extranjería
3Otra
4Permiso especial de permanencia
5Permiso por protección temporal
6Pasaporte

Estados de una solicitud

statusstatusLabel
RequestedSolicitado
SoldVendido
CancelledByCustomerCancelada por el cliente

Compare siempre contra status, no contra statusLabel: la etiqueta es texto para mostrar y puede cambiar.

Códigos de respuesta

200 / 201Todo bien.
400Datos incompletos, o producto inexistente o no asignado a su empresa.
401Token ausente, vencido o revocado.
404El recurso no existe para su empresa.
409Venció el plazo de cancelación, o ya fue vendida.

Los errores siempre traen la misma forma:

{ "message": "El plazo para cancelar esta solicitud venció el 14/08/2026 10:22." }
Sobre el 404: solo ve los datos de su propia empresa. Una solicitud de otra empresa responde 404, no 403, para no revelar siquiera que existe.

¿Dudas o necesita credenciales? Escriba a su contacto en GEM — Grupo Empresarial Masa.