Sandbox testing
Take a sandbox API key through to a confirmed enrolment, then replay create and confirm.
Use sandbox hosts and fictional student data only. Never paste a real key or a production student record.
What you will do
- Receive a sandbox provider key from StudentPay
- Use the sandbox base URL
- Generate a stable
provider_order_id - Create a checkout
- Redirect the payer to
setup_url - Complete the GoCardless sandbox BECS NZ flow
- Poll GET until
direct_debit.setup_completeistrue - Confirm with the required declarations
- Read the confirmed status and agreement references
- Replay create and confirm to prove idempotency
Setup complete is not Authorised. Mandate active can happen later and is
not required for confirm. After confirm, Salesforce creates the payment
schedule and owns collection. Your integration does not submit payments.
| Kind | Who | Credential |
|---|---|---|
| API | Your backend | Authorization: Bearer <YOUR_API_KEY> |
| Browser | Payer | Setup URL token only — never your API key |
1. Authenticate
StudentPay issues a sandbox key and a provider_code. Examples use
SANDBOX_DEMO. Keep the key on your server.
Authorization: Bearer <YOUR_API_KEY>
Content-Type: application/json
2. Check sandbox
API — no key
GET https://sandbox-api.studentpay.co.nz/v1/environment
{
"success": true,
"environment": "sandbox",
"api_base_url": "https://sandbox-api.studentpay.co.nz",
"payment_processor": "gocardless",
"payment_processor_status": "configured",
"readiness": {
"ready_for_api_calls": true
}
}
3. Create a checkout
Generate a provider_order_id you can reuse on retries. Do not change the
logical enrolment when you retry.
If StudentPay has configured your provider as catalogue-authoritative,
send course.course_code instead of inventing price and instalment maths.
See Enrolment Integration.
The sandbox walkthrough below uses SANDBOX_DEMO, which remains on the
legacy client-supplied plan contract when course.course_code is omitted.
API — your backend
POST https://sandbox-api.studentpay.co.nz/v1/provider-checkouts
Authorization: Bearer <YOUR_API_KEY>
Content-Type: application/json
Idempotency-Key: DEMO-ENROLMENT-1001
{
"provider": {
"provider_code": "SANDBOX_DEMO",
"provider_order_id": "DEMO-ENROLMENT-1001"
},
"student": {
"first_name": "Alex",
"last_name": "Student",
"email": "alex.student@example.com"
},
"course": {
"course_name": "Example Certificate"
},
"pricing": {
"course_price": 1834.25,
"amount_to_finance": 1834.25,
"upfront_payment": 0
},
"plan": {
"payment_type": "interest_free_payment_plan",
"payment_frequency": "Weekly",
"number_of_instalments": 74,
"instalment_amount": 25,
"final_instalment_amount": 9.25,
"first_payment_date": "2026-10-01"
}
}
provider.provider_code must match the key.
StudentPay validates integer-cent maths. This example is a residual plan:
73 × $25.00 + 1 × $9.25 = $1,834.25. See Payment Plans.
Create response
{
"success": true,
"idempotent_replay": false,
"provider": {
"provider_code": "SANDBOX_DEMO",
"provider_order_id": "DEMO-ENROLMENT-1001"
},
"records": {
"contact_id": "003XXXXXXXXXXXX",
"opportunity_id": "006XXXXXXXXXXXX",
"dda_id": "a0XXXXXXXXXXXXX"
},
"checkout": {
"checkout_id": "SANDBOX_DEMO-1720000000000-AB12CD34",
"status": "direct_debit_setup_required",
"requires_direct_debit": true
},
"direct_debit": {
"setup_complete": false,
"dda_id": "a0XXXXXXXXXXXXX",
"setup_url": "https://sandbox-api.studentpay.co.nz/api/dd-setup?token=<setup-token>",
"token": "<setup-token>"
}
}
Keep checkout.checkout_id, records.opportunity_id, direct_debit.dda_id,
direct_debit.setup_url, and direct_debit.token (this is
checkout.checkout_token on confirm).
setup_complete is false here. That is expected.
4. Redirect the payer to hosted setup
Browser — not your API key
Open direct_debit.setup_url as a redirect or popup. The payer completes
BECS NZ bank details on GoCardless using GoCardless sandbox test details.
This is not a StudentPay JSON API call.
Do not send Authorization: Bearer <YOUR_API_KEY> from the browser.
5. Return, then wait for setup complete
GoCardless returns the browser to StudentPay. Treat any popup message as a hint only.
API — your backend
GET https://sandbox-api.studentpay.co.nz/v1/provider-checkouts/SANDBOX_DEMO-1720000000000-AB12CD34
Authorization: Bearer <YOUR_API_KEY>
Wait until direct_debit.setup_complete is true:
{
"success": true,
"checkout": {
"checkout_id": "SANDBOX_DEMO-1720000000000-AB12CD34",
"status": "direct_debit_setup_required"
},
"direct_debit": {
"setup_complete": true,
"billing_request_status": "fulfilled",
"mandate_status": "pending_submission",
"authorisation_status": "Customer In Progress",
"authorised": false,
"dda_id": "a0XXXXXXXXXXXXX"
}
}
You may confirm while mandate_status is pending_submission or submitted
and authorised is false.
6. Confirm enrolment
API — your backend
POST https://sandbox-api.studentpay.co.nz/v1/provider-checkouts/SANDBOX_DEMO-1720000000000-AB12CD34/confirm
Authorization: Bearer <YOUR_API_KEY>
Content-Type: application/json
{
"provider": {
"provider_code": "SANDBOX_DEMO",
"provider_order_id": "DEMO-ENROLMENT-1001"
},
"checkout": {
"checkout_id": "SANDBOX_DEMO-1720000000000-AB12CD34",
"checkout_token": "<setup-token>",
"opportunity_id": "006XXXXXXXXXXXX",
"dda_id": "a0XXXXXXXXXXXXX"
},
"payment": {
"payment_method": "studentpay_payment_plan",
"first_payment_date": "2026-10-01",
"deposit_confirmed": true
},
"declarations": {
"payment_plan_accepted": true,
"information_confirmed": true,
"privacy_consent_accepted": true
}
}
Always include {checkoutId} in the path. Use direct_debit.token from
create. All three declarations and deposit_confirmed must be true.
Confirm does not collect money. After confirm, Salesforce originates any
initial-payment Charge_Schedule and the existing Direct Debit processor
collects it.
Confirm response
{
"success": true,
"checkout": { "status": "confirmed", "id": "SANDBOX_DEMO-1720000000000-AB12CD34" },
"enrolment": { "status": "complete" },
"direct_debit": {
"setup_complete": true,
"mandate_status": "pending_submission"
},
"agreement": {
"id": "a0JXXXXXXXXXXXX",
"number": "PPA-000001",
"pdf_generated": true
},
"already_confirmed": false
}
7. Replay safely
POST create again with the same provider_order_id / Idempotency-Key.
Expect idempotent_replay: true and no second enrolment.
POST confirm again. Expect already_confirmed: true and the same agreement
references.
Done
Enrolment is complete for this API when checkout.status is confirmed and
enrolment.status is complete.
What happens later, outside this API:
- Mandate may become
active/ Authorised - Salesforce creates the payment schedule
- Salesforce owns collection