Sandbox live

Errors

v1 responses use a stable envelope. Every response also has request_id and an X-Request-Id header.

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid provider checkout payload",
    "details": {
      "missing_fields": ["student.email"]
    },
    "request_id": "req_3f9c2a1b8e7d6c5a4b3d2e1f"
  },
  "request_id": "req_3f9c2a1b8e7d6c5a4b3d2e1f"
}

Send your own id with X-Request-Id when correlating logs. Otherwise StudentPay generates req_….

Authentication

Code HTTP When
MISSING_API_KEY 401 Authorization header missing or empty
INVALID_API_KEY 403 Bearer token is not a recognised provider key
PROVIDER_KEY_MISMATCH 403 Key does not match provider.provider_code

Validation

Code HTTP When
VALIDATION_ERROR 400 Required fields missing or invalid (create or confirm)

Create details may include missing_fields and invalid_fields (for example pricing.course_price, plan.first_payment_date, course.course_code). For interest_free_payment_plan, invalid_fields also includes commercial fields that do not reconcile in integer cents (course_price − upfront_payment = amount_to_finance = number_of_instalments × instalment_amount), and catalogue mismatches when a client-supplied amount does not match the resolved course.

PIC create failures that are not “unknown provider” return HTTP 403 (inactive, API disabled, Environment mismatch, or missing Account).

Enrolment Integration uses these same /v1 errors. Demo routes under /api/demos/bela-beauty/ are not part of the product contract.

Confirm requires checkout.checkout_token, checkout.opportunity_id, checkout.dda_id, payment.payment_method, payment.first_payment_date, payment.deposit_confirmed: true, and all three declaration booleans true.

Checkout token

Confirm verifies the DDA setup JWT (checkout.checkout_token).

Code HTTP When
EXPIRED_CHECKOUT_TOKEN 401 Token expired
INVALID_CHECKOUT_TOKEN 401 Token missing, malformed, or not a valid setup token

Token / identifier mismatches on confirm return HTTP 403 with a string message, for example:

  • The Opportunity ID does not match the checkout token.
  • The direct debit authority ID does not match the checkout token.
  • The provider code does not match the checkout token.

On the v1 confirm route those string errors are mapped to error.code: INTERNAL_ERROR while the HTTP status stays 403. Treat the status and message as authoritative. This mapping is a known product gap, not a dedicated mismatch code.

Not found

Code HTTP When
PROVIDER_NOT_FOUND 404 Unknown or unusable provider_code on create
CHECKOUT_NOT_FOUND 404 Checkout not found for this provider (GET), or confirm cannot load the checkout / authority

Checkout state

Code HTTP When
DIRECT_DEBIT_SETUP_INCOMPLETE 409 Confirm called before setup complete. May include billing_request_status and mandate_status
CONFLICT 409 Confirm identifiers do not match the stored checkout (provider order id, checkout id, or DDA / opportunity pairing)
IDEMPOTENCY_CONFLICT 409 Create reused provider_order_id / Idempotency-Key with a different canonical enrolment intent

DIRECT_DEBIT_SETUP_INCOMPLETE is not “not Authorised”. Wait until GET shows setup_complete: true.

Create replay of the same canonical enrolment intent returns 200 with idempotent_replay: true. See Idempotency.

Routing and server errors

Code HTTP When
METHOD_NOT_ALLOWED 405 Wrong HTTP method, or confirm without {checkoutId} in the path
INTERNAL_ERROR 500 Unexpected failure
INTERNAL_ERROR 403 Confirm token / identifier mismatch (see Checkout token). HTTP 403, not 500

Configuration

GET /v1/environment reports missing configuration by variable name in readiness.missing_required. It does not return secret values.

If GoCardless is not configured, hosted setup cannot start. Check payment_processor_status on the environment endpoint before you send payers to setup_url.

PIC Environment must match the API runtime (Sandbox vs Production). A usable PIC that is Active and API-enabled still fails closed when the Environment field does not match the host you called.

Common failures (quick map)

Situation Typical result
Missing Authorization 401 MISSING_API_KEY
Unrecognised key 403 INVALID_API_KEY
Key vs provider_code 403 PROVIDER_KEY_MISMATCH
Wrong / inactive PIC 403 or 404 PROVIDER_NOT_FOUND
Invalid or unbalanced plan 400 VALIDATION_ERROR
Unknown / mismatched course_code 400 VALIDATION_ERROR (course.course_code)
Client price or instalment override 400 VALIDATION_ERROR
Unknown checkout_id 404 CHECKOUT_NOT_FOUND
Confirm before setup_complete 409 DIRECT_DEBIT_SETUP_INCOMPLETE
Idempotent create replay (same intent) 200 idempotent_replay: true (not an error)
Same order id, different course/plan 409 IDEMPOTENCY_CONFLICT
Confirm replay 200 already_confirmed: true
Sandbox key on Production host 403 INVALID_API_KEY