---
name: paylumia-integration
description: Integrate PayLumia carrier billing (hosted checkout) into a web or mobile product. Use when the user wants to charge mobile subscribers through PayLumia, create hosted payments, handle PayLumia webhooks, sell subscriptions billed to the phone line, or prepare a PayLumia go-live review.
---

# PayLumia integration

PayLumia is Hadruvo's carrier-billing aggregator. A partner server creates a
**hosted payment**, the subscriber confirms on `pay.paylumia.com`, the operator
charges the line, and PayLumia sends a **signed webhook**. This skill walks the
developer from scoping to a go-live-ready integration.

Source of truth: https://developers.hadruvo.com (Partner API v1, hosted mode).
Never invent endpoints, fields, events or error codes that are not in the
reference files below. If something is not covered, say so and point the user
to their Hadruvo integration contact.

## How to run this skill

Work through the five steps in order. Ask one short question at a time; skip
questions the user already answered.

### 1. Scope the service

Establish, in plain words:

- **What is sold**: a subscription (daily / weekly / monthly), a consumable
  (coin pack, pass, credits) or a permanent unlock. In PayLumia this is the
  **offer type**: `SUBSCRIPTION`, `CONSUMABLE` or `NON_CONSUMABLE`.
- **Offers**: the `offerUid` values configured in the partner console (for
  example `premium_daily`). Price, currency, period and trial live on the offer;
  the code only names it.
- **Presentation**: `redirect` (default, works everywhere) or `embedded` (the
  checkout mounted in the partner's page).
- **Stack**: server language/framework (Node.js, PHP, Python, other), how
  orders/users are stored, and where webhooks will be received.
- **Market**: country and operator (discover what is available at runtime with
  `GET /v1/capabilities` — never hard-code consent methods).

### 2. Credentials and environments

Two separate deployments of one application (credentials never cross):

| Env | API | Checkout | Client ID | Operator |
| --- | --- | --- | --- | --- |
| Sandbox | `https://api.sandbox.paylumia.com` | `https://pay.sandbox.paylumia.com` | `plm_test_` | Mock only |
| Production | `https://api.paylumia.com` | `https://pay.paylumia.com` | `plm_live_` | Live Orange |

- Secrets are shown once. Store them in a secret manager or environment
  variables (`PAYLUMIA_CLIENT_ID`, `PAYLUMIA_CLIENT_SECRET`,
  `PAYLUMIA_WEBHOOK_SECRET`). Never ship them in a mobile app or a web page.
- Each environment has **its own webhook URL and signing secret**, set in the
  console. The create request never carries a notify URL.

Details: `references/authentication.md`, `references/environments-and-go-live.md`.

### 3. Generate the code

Produce, for the user's stack:

1. **Token client** — `POST /oauth2/token` (client credentials), cache for
   ~1 hour, refresh shortly before expiry.
2. **Create payment** — `POST /v1/payments` with `mode: "HOSTED"`, `offerUid`,
   `returnUrl`, optional `presentation`, `prefill`, `operator`, `metadata`
   (put the partner's order id in `metadata`). Always send an
   `Idempotency-Key` (8–255 chars, stable per order/attempt). Then redirect to
   or embed `data.checkoutUrl`.
3. **Webhook endpoint** — read the **raw body**, verify `PayLumia-Signature`
   (`t={unix},v1={hex hmac}` over `{t}.{rawBody}`, HMAC-SHA256, 5-minute
   tolerance, constant-time compare), store the event, answer `2xx` fast,
   process idempotently. Grant on `payment.succeeded` / `entitlement.granted`,
   revoke on `entitlement.revoked`.
4. **Return page** — `returnUrl` receives `paymentUid` and `status` as hints
   only. Show a friendly screen and confirm server-side with the webhook or
   `GET /v1/payments/{paymentUid}`.
5. **Subscriptions** (if applicable) — read, cancel (`NOW` or `PERIOD_END`) and
   resume endpoints; react to `entitlement.*` and `subscription.*` events.

Samples: `references/hosted-checkout.md`, `references/webhooks.md`,
`references/subscriptions.md`. Error handling: `references/errors.md`.

Forbidden in hosted mode (reject if the user asks): sending `amount`, a bare
`msisdn` (use `prefill.msisdn`), `productUid` or `notifyUrl` in the create
body; granting access from the return URL alone; signing query strings or the
checkout URL.

### 4. Comply

Check the partner's UX and code against these rules and call out any gap:

- The offer name, price and billing period are shown **before** the
  subscriber is sent to checkout.
- A clear way to cancel a subscription exists in the product.
- Consent happens only on the PayLumia checkout host for that environment; prefilling the number never
  replaces consent.
- Access is granted from a verified webhook or a server-side read.

### 5. Validate for go-live

Run the checklist in `references/environments-and-go-live.md` with the user
and produce a short report: passed / to fix. Suggest test cases: success,
decline (`payment.failed`), abandoned session (`EXPIRED`), cancel before
completion, duplicate webhook delivery, bad signature, token expiry.
When everything passes, tell them to ask their Hadruvo contact for the
go-live review.

## Reference files

- `references/api-overview.md` — base URLs, conventions, endpoint list
- `references/authentication.md`
- `references/hosted-checkout.md` — create, fields, response, offer types, checkout experience
- `references/payment-lifecycle.md`
- `references/webhooks.md`
- `references/subscriptions.md`
- `references/errors.md`
- `references/environments-and-go-live.md`
- `references/paylumia-hosted.openapi.yaml` — machine-readable contract
