S1mpl3 Iniciar sesiónPedir acceso
Docs / Referencia de la API · v1

API de S1mpl3

Confirmá desde tu sistema si un SINPE Móvil llegó, por cuánto y si ya se usó. Todo responde JSON en español y se llama desde tu servidor.

● API v1 en líneahttps://s1mpl3.net/api/v1Probar en vivoObtener clave

01Antes de empezar#

  1. Pedí una cuenta y entrá al panel.
  2. Conectá en Buzones el correo donde te llegan los avisos del banco.
  3. Generá una clave en Claves API y guardala en tu servidor.

Todas las rutas cuelgan de esta URL base y responden JSON:

02Autenticación#

Mandá la clave en cada solicitud, en Authorization: Bearer sk_live_… o en la cabecera X-API-Key. Las claves se muestran una sola vez; en el servidor solo guardamos su hash SHA-256. Si perdés una, revocala y generá otra.

Nunca desde el navegador. La clave da acceso a tus pagos: llamá a la API solo desde tu servidor.

Cada clave tiene un límite de 120 solicitudes por minuto. Al pasarlo recibís 429 con Retry-After: 30.

Cabeceras
Authorization: Bearer sk_live_…
# o bien
X-API-Key: sk_live_…

03Verificar un pago#

POST/verificar

Busca el SINPE por los últimos 4 dígitos del comprobante y, si lo encuentra disponible, lo marca como usado en la misma operación. Un segundo intento con el mismo comprobante responde ya_utilizado.

CampoTipoDescripción
ultimos4 obligatoriostringÚltimos 4 dígitos de la referencia. Mandalo como texto: "0427" conserva el cero inicial.
monto recomendadonumber | stringMonto esperado en colones (12500 o "12,500.00"). Evita que dos pagos se confundan.
telefonostringTeléfono de origen, para desempatar.
referenciastringReferencia completa del comprobante.
referencia_externastringTu número de orden; queda guardado junto al SINPE.
consumirbooleanPor defecto true. Con false solo consulta.
# Verificar y marcar como usado
curl -X POST https://s1mpl3.net/api/v1/verificar \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{"ultimos4":"0427","monto":12500,"referencia_externa":"ORD-1042"}'
200Verificado
{
  "verificado": true,
  "consumido": true,
  "transaccion": {
    "id": 42,
    "referencia": "2026101800000000000000427",
    "ultimos4": "0427",
    "monto": 12500,
    "moneda": "CRC",
    "telefono": "60000001",
    "nombre": "ROCIO EJEMPLO MORA",
    "entidad": "Banco de Costa Rica",
    "motivo": "ORD-1042",
    "banco": "BCR",
    "fuente": "email",
    "fecha": "2026-10-18T21:02:00.000Z",
    "recibido_en": "2026-10-18T21:02:31.000Z",
    "estado": "utilizado",
    "utilizado_en": "2026-10-18T21:03:10.000Z",
    "referencia_externa": "ORD-1042"
  }
}

04Qué puede salir mal#

Los errores responden "verificado": false, un código en error y un mensaje legible.

HTTPerrorQué significa
404no_encontradoNo llegó ningún SINPE con esos dígitos en los últimos 30 días.
409ya_utilizadoEse comprobante ya se usó. Trae utilizado_en y referencia_externa.
409ambiguoVarios SINPE disponibles comparten esos 4 dígitos. Mandá monto, telefono o referencia.
422monto_no_coincideExiste, pero por otro monto. Trae monto_recibido y moneda.
400parametros_invalidosultimos4 no tiene 4 dígitos o el monto no es válido.
401no_autorizadoFalta la clave o está revocada.
403cliente_inactivoLa cuenta está inactiva.
429demasiadas_solicitudesPasaste el límite. Esperá y reintentá con espera exponencial.
500error_internoAlgo falló de nuestro lado.
409ambiguo
{
  "verificado": false,
  "error": "ambiguo",
  "mensaje": "Varios SINPE coinciden con esos 4 dígitos. Envíe monto, telefono o la referencia completa para desambiguar.",
  "coincidencias": 2
}
422monto_no_coincide
{
  "verificado": false,
  "error": "monto_no_coincide",
  "mensaje": "Se encontró un SINPE con esos dígitos pero por un monto distinto (CRC 8 000,00).",
  "monto_recibido": 8000,
  "moneda": "CRC"
}

05Consultar sin marcar#

GET/verificar/{ultimos4}

Igual que verificar, pero nunca marca el comprobante como usado. Acepta ?monto=, ?telefono= y ?referencia= en la URL. Sirve para mostrarle al cliente que su pago llegó antes de cerrar la orden.

curl
curl "https://s1mpl3.net/api/v1/verificar/0427?monto=12500" \
  -H "Authorization: Bearer sk_live_…"
200Solo consulta
{
  "verificado": true,
  "consumido": false,
  "transaccion": {
    "id": 42,
    "referencia": "2026101800000000000000427",
    "ultimos4": "0427",
    "monto": 12500,
    "moneda": "CRC",
    "telefono": "60000001",
    "nombre": "ROCIO EJEMPLO MORA",
    "entidad": "Banco de Costa Rica",
    "motivo": "ORD-1042",
    "banco": "BCR",
    "fuente": "email",
    "fecha": "2026-10-18T21:02:00.000Z",
    "recibido_en": "2026-10-18T21:02:31.000Z",
    "estado": "disponible",
    "utilizado_en": null,
    "referencia_externa": null
  }
}

06Transacciones#

GET/transacciones

Los SINPE recibidos, del más reciente al más viejo.

ParámetroDescripción
estadodisponible o utilizado.
desdeFecha ISO 8601; solo lo recibido desde ese momento.
limitCuántas devolver: 50 por defecto, 200 como máximo.
offsetPara paginar.
GET/transacciones/{referencia}

Una transacción por su referencia completa. Si no existe responde 404 con no_encontrado.

curl
curl "https://s1mpl3.net/api/v1/transacciones?estado=disponible&limit=20" \
  -H "Authorization: Bearer sk_live_…"
200OK
{
  "transacciones": [
    {
      "id": 42,
      "referencia": "2026101800000000000000427",
      "ultimos4": "0427",
      "monto": 12500,
      "moneda": "CRC",
      "telefono": "60000001",
      "nombre": "ROCIO EJEMPLO MORA",
      "entidad": "Banco de Costa Rica",
      "motivo": "ORD-1042",
      "banco": "BCR",
      "fuente": "email",
      "fecha": "2026-10-18T21:02:00.000Z",
      "recibido_en": "2026-10-18T21:02:31.000Z",
      "estado": "disponible",
      "utilizado_en": null,
      "referencia_externa": null
    }
  ]
}

07Sincronizar#

POST/sincronizar

Fuerza una lectura inmediata de tus buzones activos. Normalmente no hace falta: los leemos cada 30 s. Devuelve, por buzón, cuántos correos se leyeron (fetched), cuántos SINPE nuevos se registraron (registered), cuántos se descartaron y cuántos ya existían.

curl
curl -X POST https://s1mpl3.net/api/v1/sincronizar \
  -H "Authorization: Bearer sk_live_…"
200OK
{
  "ok": true,
  "buzones": [
    {
      "buzon": 1,
      "fetched": 3,
      "registered": 1,
      "rejected": 2,
      "duplicates": 0
    }
  ]
}

08SMS reenviados#

POST/ingest/sms

Para bancos que avisan por SMS: una app reenviadora en el teléfono del comercio manda el texto del mensaje y lo registramos como SINPE.

CampoDescripción
texto obligatorioEl SMS tal como llegó.
bancoPista del banco (por ejemplo BAC).
remitenteNúmero o nombre que envió el SMS.

Responde 201 si lo registró, 200 si esa referencia ya existía, y 422 con formato_no_reconocido o no_es_credito si el texto no sirve.

curl
curl -X POST https://s1mpl3.net/api/v1/ingest/sms \
  -H "Authorization: Bearer sk_live_…" -H "Content-Type: application/json" \
  -d '{"banco":"BAC","texto":"BAC: Ha recibido una transferencia SINPE Movil por CRC 12,500.00 de ROCIO EJEMPLO MORA. Ref: 2026101800000427. Detalle: ORD-1043"}'
201Creada
{
  "creada": true,
  "transaccion": {
    "id": 42,
    "referencia": "2026101800000427",
    "ultimos4": "0427",
    "monto": 12500,
    "moneda": "CRC",
    "telefono": null,
    "nombre": "ROCIO EJEMPLO MORA",
    "entidad": "BAC",
    "motivo": "ORD-1043",
    "banco": "BAC",
    "fuente": "sms",
    "fecha": null,
    "recibido_en": "2026-10-18T21:02:31.000Z",
    "estado": "disponible",
    "utilizado_en": null,
    "referencia_externa": null
  }
}

09Sandbox#

POST/sandbox/transacciones

Solo para cuentas con el modo sandbox habilitado (si no, responde 403 sandbox_desactivado). Simula un SINPE recibido para que pruebes la integración sin mover plata. En el panel, el Simulador hace lo mismo con escenarios listos (duplicado, monto distinto, no llegó, varios coinciden) y te muestra el payload del webhook. monto es obligatorio; referencia, nombre, telefono, motivo, entidad y moneda son opcionales.

curl
curl -X POST https://s1mpl3.net/api/v1/sandbox/transacciones \
  -H "Authorization: Bearer sk_live_…" -H "Content-Type: application/json" \
  -d '{"monto":12500,"motivo":"ORD-1043","referencia":"2026101800000000000000427"}'
201Creada
{
  "creada": true,
  "transaccion": {
    "id": 42,
    "referencia": "2026101800000000000000427",
    "ultimos4": "0427",
    "monto": 12500,
    "moneda": "CRC",
    "telefono": null,
    "nombre": "CLIENTE DE PRUEBA",
    "entidad": "SANDBOX",
    "motivo": "ORD-1043",
    "banco": "SANDBOX",
    "fuente": "sandbox",
    "fecha": "2026-10-18T21:02:00.000Z",
    "recibido_en": "2026-10-18T21:02:31.000Z",
    "estado": "disponible",
    "utilizado_en": null,
    "referencia_externa": null
  }
}

10Webhooks#

Registrá una URL en el panel y te mandamos un POST con JSON por cada evento al que la suscribas.

EventoCuándo se envía
sinpe.recibidoEntró un SINPE (crédito) a uno de tus buzones, por SMS o por el sandbox. Es el evento por defecto.
sinpe.utilizadoUn comprobante se verificó con consumir: true y quedó marcado como usado (desde la caja o la API).
pingPrueba manual desde el panel (botón «Ping»). transaccion viene en null.
CabeceraContenido
X-S1mpl3-EventEl nombre del evento.
X-S1mpl3-TimestampSegundos Unix del envío.
X-S1mpl3-Signaturesha256= + HMAC-SHA256 en hex de timestamp + "." + cuerpo, con el secreto del webhook.

Respondé con un 2xx en menos de 10 s. Si no, reintentamos con espera creciente (30 s, 1 min, 2 min… hasta 1 h entre intentos), con un máximo de 8 intentos. En el panel ves cada entrega con su request, la respuesta de tu servidor y los intentos, y podés reenviarla o rotar el secreto.

El webhook solo avisa. Para liberar el pedido llamá a /verificar con consumir en true: así el comprobante queda marcado como usado de forma atómica.
POSTCuerpo
{
  "evento": "sinpe.recibido",
  "id_entrega": 15,
  "enviado_en": "2026-10-18T21:02:35.000Z",
  "transaccion": {
    "id": 42,
    "referencia": "2026101800000000000000427",
    "ultimos4": "0427",
    "monto": 12500,
    "moneda": "CRC",
    "telefono": "60000001",
    "nombre": "ROCIO EJEMPLO MORA",
    "entidad": "Banco de Costa Rica",
    "motivo": "ORD-1042",
    "banco": "BCR",
    "fuente": "email",
    "fecha": "2026-10-18T21:02:00.000Z",
    "recibido_en": "2026-10-18T21:02:31.000Z",
    "estado": "disponible",
    "utilizado_en": null,
    "referencia_externa": null
  }
}
// Express: el cuerpo tiene que llegar crudo para calcular la firma
import crypto from "node:crypto";

app.post("/webhooks/s1mpl3", express.raw({ type: "application/json" }), (req, res) => {
  const ts = req.get("X-S1mpl3-Timestamp") || "";
  const firma = req.get("X-S1mpl3-Signature") || "";
  const esperada = "sha256=" + crypto
    .createHmac("sha256", process.env.S1MPL3_WEBHOOK_SECRET)
    .update(ts + "." + req.body.toString("utf8"))
    .digest("hex");
  const valida = firma.length === esperada.length &&
    crypto.timingSafeEqual(Buffer.from(firma), Buffer.from(esperada));
  if (!valida || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401);
  const evento = JSON.parse(req.body);
  // evento.transaccion.ultimos4, evento.transaccion.monto…
  res.sendStatus(200);
});

11Cómo leemos los pagos#

  • Conectás el buzón al que tu banco manda los avisos, con una contraseña de aplicación. Se guarda cifrada con AES-256-GCM y solo leemos: nunca borramos ni enviamos correos.
  • Revisamos el buzón cada 30 s. El correo tiene que venir de un dominio bancario conocido (o de un remitente que agregues) y pasar DKIM, ARC o SPF; si no, queda en «Correos descartados» con el motivo.
  • Plantillas propias: Banco de Costa Rica, BAC Credomatic, Banco Nacional (leemos el PDF adjunto) y Banco Popular (también por SMS). Para Promerica, Davivienda, Scotiabank, Coopenae, Mutual Cartago, Grupo Mutual, Lafise, Banco Cathay, Banco BCT usamos una plantilla genérica por etiquetas.
  • Guardamos monto, teléfono, nombre, entidad, motivo y referencia. Los avisos de dinero que sale (débitos) se guardan pero nunca se pueden verificar ni disparan webhooks.
  • No pedimos credenciales bancarias y no podemos mover dinero.

12Buenas prácticas#

  • Mandá siempre el monto: 4 dígitos solos pueden coincidir entre pagos.
  • Pedile al cliente que escriba su número de orden en el motivo del SINPE y usalo como referencia_externa.
  • Ante ambiguo, pedí el teléfono o la referencia completa.
  • Ante 429, esperá y reintentá con espera exponencial.
  • Verificá la firma de cada webhook y descartá los que tengan un timestamp viejo.
  • Guardá la clave en una variable de entorno, nunca en el código del navegador ni en el repositorio.