Sandbox Certification¶
Certification is the gate between sandbox and production: you demonstrate the five scenarios below against the sandbox, submit your evidence, and FSRI reviews it before issuing production credentials. It exists to protect both sides — a partner who passes certification won't discover auth, isolation, or completion bugs in front of live learners.
Prerequisites: a completed sandbox integration (you can run the Quick Start end-to-end), and your technical contact registered with FSRI.
How Certification Works¶
- Build against sandbox until the five scenarios below all pass in your integration.
- Record evidence as you run each scenario — request/response logs with credentials redacted, or a screen recording of your test suite.
- Submit the evidence bundle to your FSRI integration contact.
- FSRI reviews — verifying your API interactions server-side against our logs, not just your submission.
- Outcome: pass → production credentials issued; gaps → you get a specific list to fix and resubmit. Partial passes carry over; only failed scenarios are re-reviewed.
Timeline
Review typically completes within 5 business days of submission; resubmissions within 3. Plan certification at least two weeks before your target production date to absorb a fix cycle.
Scenario 1 — Authentication¶
Proves: you handle the full credential lifecycle correctly.
| # | Demonstrate | Pass criteria |
|---|---|---|
| 1.1 | Obtain a token via client_credentials | 200 from the token endpoint; JWT with scope containing partner-api/read partner-api/write |
| 1.2 | Scope verification | Decoded token's scope matches what you requested; an authenticated call succeeds with it |
| 1.3 | Token refresh behavior | Your integration re-mints before/at expiry without minting per-request (logs showing one token reused across calls, then a refresh) |
| 1.4 | Dual-credential handling | A request without x-api-key fails 403; with both headers it succeeds |
Fail examples: minting a token for every call · retrying 401 in an infinite loop · API key present on some requests but not others.
Scenario 2 — User Registration & Lifecycle¶
Proves: learner identity management is correct, including the privacy paths.
| # | Demonstrate | Pass criteria |
|---|---|---|
| 2.1 | Register a new user | 201 with UUID; UUID persisted on your side |
| 2.2 | Duplicate registration | Registering the same email again returns the same user — no duplicate local records |
| 2.3 | Profile update | PATCH with application/merge-patch+json changes only the sent fields |
| 2.4 | Deactivate + reactivate | status: inactive → user-scoped calls rejected → status: active restores them |
Fail examples: treating a duplicate registration as an error state · PATCH with application/json worked around by re-sending whole profiles.
Scenario 3 — Content Access¶
Proves: catalog consumption and the content-delivery model work end to end.
| # | Demonstrate | Pass criteria |
|---|---|---|
| 3.1 | Catalog listing | Organizations, categories, and courses listed with correct pagination handling |
| 3.2 | Module access | GET /modules/{id}/content with a registered UUID returns a content URL; content renders in your embed |
| 3.3 | Progress auto-creation | After 3.2, GET /course-progresses shows the auto-created in_progress record — without you creating anything |
| 3.4 | URL expiry handling | Show how your player handles expires_at (refresh-url during playback, or a documented click-time-fetch policy) |
Fail examples: persisted/cached content URLs · hardcoded module IDs that break after a sandbox refresh.
Scenario 4 — Progress & Transcripts¶
Proves: you read the learning record correctly and deliver credentials.
| # | Demonstrate | Pass criteria |
|---|---|---|
| 4.1 | Progress query | GET /course-progresses displayed/consumed for a user with activity; delta-sync used for scheduled polling |
| 4.2 | Completion reporting | Video/document module: your "Mark as Complete" calls POST /modules/{id}/complete → 202; repeat call → 202 with no error surfaced to the learner |
| 4.3 | Transcript PDF | GET /transcript/pdf retrieved and served as a valid PDF |
| 4.4 | Certificate PDF | For a transcript with certificateAvailable: true: certificate retrieved via GET /transcripts/{id}/certificate/pdf |
Fail examples: calling /complete for SCORM modules · writing progress state locally and letting it drift from the API's record.
Scenario 5 — Error Handling¶
Proves: your integration degrades safely instead of amplifying failures.
| # | Demonstrate | Pass criteria |
|---|---|---|
| 5.1 | 401 handling |
Induce one (expired/garbage token): your client refreshes and retries once, then surfaces the failure — no retry storm |
| 5.2 | 404 handling |
A nonexistent/foreign UUID is handled as "not found" without retries |
| 5.3 | 429 handling |
Demonstrate exponential backoff (test-harness simulation acceptable if sandbox limits are impractical to hit) |
| 5.4 | Validation errors | A 400 with violations[] maps to actionable feedback in your system, not a generic crash |
Fail examples: unbounded retry loops on any 4xx · credentials appearing in logged error output.
Evidence Format¶
For each numbered item, capture: timestamp (with timezone) · request (method, URL, headers minus secrets, body) · response (status + body; PDFs by filename/size). A structured log export or annotated Postman Collection Runner results both work.
Redact your credentials
Redact Authorization, x-api-key, and all secrets everywhere. Submissions containing live credentials are failed on the spot and the credentials rotated.
After Certification¶
- Production credentials are issued over the same secure channel as sandbox's.
- Go-live is coordinated with your FSRI contact — see the Go-Live Runbook (partner area).
- Re-certification is only required for material integration changes (new endpoints consumed, auth handling rewritten) — routine feature work on your side doesn't need it.