droprails / index.html — v0.1 — 2026-05-09
live
00endpoint /buyPOST /api/v1/buy
POST/api/v1/buy

La llamada única. Internamente verificamos la credencial MPP, emitimos la tarjeta upstream (start + confirm con polling de recuperación) y devolvemos el payload de canje dentro de un Payment-Receipt firmado.

01headers
Idempotency-Keyreq
string
provisto por el agente, 1–128 chars. Requerido. Misma key + mismo body = misma respuesta.
Authorization
string
`Payment <credential>` una vez obtenida. Sin esto recibes 402.
Content-Typereq
string
application/json
02body de la solicitud
skureq
string
del /api/v1/catalog
qty
integer
v0.1 solo soporta 1
amount
integer
unidades menores (centavos). Requerido para items de monto variable.
metadata
object
opaco, contabilidad del agente
03la máquina de estadosascii
pending
  ↓ (mppx verified the credential before our handler ran)
mpp_verified
  ↓ upstream.startOrder({ items: [{ sku, quantity, amount? }] })
upstream_started
  ↓ upstream.confirmOrder(orderId)              ← 18s wall-clock
upstream_confirming
  ├── status=4  →  fulfilled
  ├── status=3  →  retry per-giftcard via upstream
  │              └── all succeed → fulfilled
  │              └── any remain  → refund_required
  ├── status=2  →  upstream_polling
  │              └── GET /order every 1s up to 25s budget
  ├── status=1  →  failed (no money moved)
  └── timeout   →  upstream_polling
04respuesta del happy path200 OK
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: private, no-store
Payment-Receipt: eyJtZXRob2QiOiJ0ZW1wbyIsInN0YXR1c...

{
  "order_id": "01HZ...",
  "status": "fulfilled",
  "redemption": {
    "type": "text",
    "value": "249032",
    "legend": "Para usar tu tarjeta...",
    "expires_at": 1715201599
  },
  "amount": { "total": 30000, "currency": "MXN" },
  "rail": "tempo",
  "issued_at": 1746000000
}
05contrato de idempotencia
  • misma key, mismo body → 200 con la respuesta cacheada
  • misma key, body distinto → 409 idempotency.conflict
  • las keys persisten 7 días
06la postura refund_requiredops

Cuando upstream cumple parcialmente (status=3 con reintentos agotados) o se excede el presupuesto de polling, la orden termina en refund_required. El dinero salió pero no podemos devolver el(los) código(s) al agente. Las tarjetas no cancelan una vez emitidas — los reembolsos viajan por la vía MPP. v0.1 los expone en /api/v1/health; un operador concilia. v0.2 automatiza reembolsos por vía.