Sandbox live

Idempotency

Create and confirm are safe to retry. They do not emit outbound webhooks again on replay.

Create checkout

  1. Prefer the Idempotency-Key header (max 255 characters)
  2. Otherwise StudentPay uses {provider_code}:{provider_order_id}
POST /v1/provider-checkouts
Idempotency-Key: DEMO-ENROLMENT-1001
Authorization: Bearer <YOUR_API_KEY>

If a checkout already exists for that provider and provider order id (or checkout id), and the canonical enrolment intent is unchanged, the API returns 200 with:

{
  "success": true,
  "idempotent_replay": true,
  "idempotency_key": "DEMO-ENROLMENT-1001"
}

No additional student, checkout, or direct-debit authority records are created.

While the checkout is still open, a replay may remint a fresh direct_debit.setup_url and direct_debit.token. Use the latest URL and token.

checkout.created is sent only on the first create, not on replay.

Same order id, different payload

Replay is keyed on provider + provider_order_id (or Idempotency-Key).

StudentPay then compares canonical enrolment intent, not raw JSON ordering:

  • course name
  • course price
  • upfront amount
  • amount to finance
  • regular instalment
  • number of instalments
  • payment frequency
  • first payment date

For catalogue-authoritative providers those commercial fields are the server-resolved values, not whatever duplicate money the client tried to send.

If the canonical intent is the same, create returns the original checkout (idempotent_replay: true).

If the canonical intent is materially different, create returns 409 IDEMPOTENCY_CONFLICT. It does not create a second financial record and it does not replace the original enrolment.

Supported contract: reuse the original logical enrolment for the same provider_order_id. Do not use one order id to represent two different enrolments.

Confirm

If the checkout is already confirmed, confirm returns 200 with already_confirmed: true and the existing agreement references.

It does not:

  • create a second Payment Plan Agreement
  • generate a second PDF
  • create a second payment schedule
  • emit checkout.confirmed or agreement.generated again

You can safely retry confirm after a network timeout.