> ## Documentation Index
> Fetch the complete documentation index at: https://docs.simplepay.mx/llms.txt
> Use this file to discover all available pages before exploring further.

# Context pack

> Bloque de contexto compacto para pegar en un LLM antes de pedirle que implemente SimplePay correctamente.

Copia este bloque cuando quieras que un agente implemente SimplePay sin perder las reglas importantes.

```txt SimplePay integration context theme={"theme":{"light":"github-light","dark":"github-dark"}}
SimplePay public API:
- Base URL: https://api.simplepay.mx
- Auth: Authorization: Bearer ${SIMPLEPAY_API_KEY}
- Sandbox keys look like spk_sandbox_...
- Hosted checkout URLs are on https://checkout.simplepay.mx
- API contract: /openapi.json

Security rules:
- Never expose API keys in browser/mobile code.
- Never commit, print or persist raw secrets.
- Use only documented public SimplePay endpoints.
- Do not put secrets, payment credentials or raw payment data in metadata.
- Use sandbox first.

Idempotency:
- Include Idempotency-Key on writes.
- Use deterministic keys from business IDs.
- Examples: order_123_checkout_v1, booking_456_refund_v1.
- Retry 5xx/429 only with the same idempotency key.

Hosted Checkout:
- Endpoint: POST /v1/hosted-checkout/sessions
- Required body: currency, success_url, line_items.
- line_items use amount in minor units.
- Store response id spcs_... and url.
- Redirect user to session.url.
- success_url is UX only, not proof of payment.
- Confirm final state by webhook or API read.

Payment Links:
- Endpoint: POST /v1/payment-links
- Use for invoices, async sales, manual collection.
- Store splink_... and URL.
- Use max_payments: 1 for one-off invoices.

Refunds:
- Endpoint: POST /v1/refunds
- Use SimplePay-managed payment_intent references.
- Use Idempotency-Key.
- For Bookable refunds, prefer POST /v1/bookable-payments/bookings/{id}/refund.

Bookable Payments:
- Product for reserved inventory where payment confirms booking.
- Merchant owns login, discovery and calendar UI.
- SimplePay owns availability math, temporary holds, checkout and booking confirmation.
- Core objects: product, booking_resource, availability_schedule, availability_rule, availability_override, booking_blackout, booking_event_type, booking_hold, booking.
- Shortcut setup: POST /v1/bookable-payments/setup.
- Slots: GET /v1/bookable-payments/event_types/{id_or_slug}/slots.
- Atomic checkout: POST /v1/bookable-payments/bookings.
- Split flow: POST /v1/bookable-payments/holds then POST /v1/bookable-payments/holds/{id}/payment.
- Booking remains pending until payment webhook projection confirms it.
- Deliver voucher/access only after booking.confirmed or GET booking returns status=confirmed.

Webhook endpoints:
- Configure with POST /v1/webhook_endpoints.
- Payload shape: { "id": "...", "type": "...", "data": { ... } }
- Header: SimplePay-Signature: t=<unix>,v1=<hex hmac>
- Signature payload: `${timestamp}.${rawBody}`
- Algorithm: HMAC SHA-256 with webhook signing secret.
- Verify raw body before JSON parsing side effects.
- Deduplicate by event.id.
- Respond 2xx after durable persistence.
- Replay with POST /v1/events/{id}/replay.

Important Bookable events:
- booking.hold_created
- booking.hold_released
- booking.confirmed
- booking.expired
- booking.cancelled
- booking.rescheduled
- booking.refunded
- booking.partially_refunded
- booking.no_show
- product.updated
- customer.updated
- booking_event_type.updated

Implementation deliverables:
- Backend endpoint to create checkout or booking checkout.
- Env vars and secret handling.
- Persistence of SimplePay IDs.
- Webhook handler with HMAC verification and idempotency.
- Tests for signature verification, duplicate events and retry/idempotency.
- Sandbox smoke instructions.
```

## Minimal checkout request

```json request theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "currency": "mxn",
  "success_url": "https://example.com/success?session_id={CHECKOUT_SESSION_ID}",
  "cancel_url": "https://example.com/cart",
  "client_reference_id": "order_1001",
  "line_items": [
    {
      "name": "Producto demo",
      "amount": 50000,
      "quantity": 1
    }
  ],
  "metadata": {
    "order_id": "order_1001"
  }
}
```

## Minimal webhook verification

```ts verify-simplepay.ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import crypto from "node:crypto";

export function verifySimplePaySignature(
  rawBody: string,
  header: string,
  secret: string,
) {
  const values = Object.fromEntries(
    header.split(",").map((part) => {
      const [key, value] = part.split("=");
      return [key, value];
    }),
  );

  const timestamp = Number(values.t);
  const signature = values.v1;

  if (!timestamp || !signature) {
    throw new Error("Invalid SimplePay-Signature");
  }

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  if (
    !crypto.timingSafeEqual(
      Buffer.from(signature, "hex"),
      Buffer.from(expected, "hex"),
    )
  ) {
    throw new Error("Invalid SimplePay signature");
  }
}
```

<Info>
  Para shapes exactos, no adivines. Lee `/openapi.json` y genera tipos desde
  OpenAPI.
</Info>
