Skip to content

Integration checklist

What a finished integration looks like. Every line is something an integration has shipped without, and paid for.

Keys

  • [ ] The key lives on the server, in a secret store, never in a repository or a browser.
  • [ ] Each server has its own key, with only the scopes it needs.
  • [ ] Somebody owns rotation: the key has a lifetime, or a date in a calendar.
  • [ ] The base URL and the key are both configuration, so going live is a config change.

Charges

  • [ ] Every POST /v1/charges and POST /v1/pos/charges carries an Idempotency-Key derived from your order or sale id, and retries reuse it.
  • [ ] processing is treated as "unknown", never as failed.
  • [ ] Orders are fulfilled on charge.succeeded (or a poll returning succeeded), never on a 201 from create.
  • [ ] 503 and 429 are retried with the same key and a backoff; 4xx is never retried unchanged.
  • [ ] PamoPay-Request-Id is logged on every call.

Webhooks

  • [ ] The handler verifies PamoPay-Signature over the raw body and checks t within five minutes.
  • [ ] It deduplicates on id (ev_…) and tolerates out-of-order and repeated events.
  • [ ] It answers 2xx within ten seconds and does the work afterwards.
  • [ ] A catch-up job reads GET /v1/events?type=charge.succeeded after any outage.

Money

  • [ ] Reconciliation uses net_minor against the bank and amount_minor against the order book.
  • [ ] Code shared between /v1/charges and /v1/pos/charges reads both fee_minor and mdr_minor.
  • [ ] Bills: control_number stored raw, control_number_printed on the slip; reconciliation keys on customer_ref and data.bill.id.

Sandbox

  • [ ] The sandbox run covers all five trigger numbers, especially …004 and …005.
  • [ ] A retry was tested: the same key twice returns the same id; a different amount under it is 409.
  • [ ] A read-only key was tried against POST /v1/charges and got FORBIDDEN_SCOPE, so the scope check is known to work.

Every code, scope and route on this site is rendered from the API's own source.