Security & ownership
Ownership is a set of checks, not a promise page.
This page says what Coursio isolates, what an export contains, how a payment callback becomes access, and which decisions are still open. Where something is undecided it is marked undecided — a blank in the right place is worth more than a confident sentence.
How to read the states on this page
- Implemented — built into the product and true for every school on day one.
- Launch-country dependent — the mechanism exists; who acts as merchant or handles tax follows the country you launch in.
- Decision pending — not settled. The product labels the state instead of showing a number nobody measured.
Chain of evidence
Four links, each checkable
School isolation
Every record that belongs to a school carries that school, and every read is scoped to it. Two schools never share a students table, a thread, an order or an email list.
ImplementedSigned playback
A lesson URL is signed against one enrollment and expires. A forwarded link opens nothing, and a revoked order closes playback the same day.
ImplementedImmutable completion
Lessons completed and attempts scored are frozen at issue time. Editing the course later changes what the next learner does, not what a past learner finished.
ImplementedPortable credential proof
A public code resolves to course, school and date — and keeps resolving after export. The learner's email is never part of the public proof.
Implemented · signing custody pending
Each link is something you can test on your own school in an afternoon. None of it is a third-party audit, and this page does not claim one.
A school is a tenant, not a folder
Isolation is not a filter applied to a shared pool. Two schools have no shared surface where their learners, threads or orders could meet, so there is no place for a leak to happen and no report that could accidentally merge them.
Northstar Studio
learn.northstar.example
- Courses, modules and lesson media
- Students, enrollments and progress
- Community threads and lifecycle email
- Offers, orders and affiliate commissions
- Certificates issued in its own name
No crossing
Field Notes Academy
school.fieldnotes.example
- Its own catalog, on its own domain
- Its own learner accounts, even for the same person
- Its own threads, never a shared feed
- Its own merchant relationship and ledger
- Its own certificate codes and revocations
Operator plane
Above the schools, not inside them
The operator control plane administers schools as records. It is a separate surface with its own neutral interface, and it does not inherit a school's branding, its learner sessions or its playback identity.
Can do
- Provision and suspend a school
- Read plan and platform-fee state
- Run a full export of one tenant
- Resolve a support request against one school
Cannot do
- Browse learners across schools
- Read a community thread as a member
- Assume a learner's playback identity
- Move content or students between schools
One caveat stated plainly: infrastructure operators can always reach the database that stores the data — that is true of every hosted platform, including this one. What Coursio commits to is that the product exposes no path across the boundary, and that operator actions on a tenant are recorded against that tenant.
Export
Leaving is a supported action
An export you cannot rebuild a school from is a backup, not an export. This is what a Coursio tenant export contains and what stays true after you have it.
| What | Format | After export |
|---|---|---|
| Course structure | JSON | Modules, lesson order, drip rules and visibility, per course. |
| Lesson content | JSON + files | Rich text, downloads and a media manifest naming every video and audio asset. |
| Enrollments | CSV | Learner, course, access state and the payment event that granted it. |
| Progress and attempts | CSV | Per-lesson completion, quiz attempts and scores, with timestamps. |
| Orders | CSV | Offer, amount, currency and state, including refunded and failed. |
| Community threads | JSON | Course-scoped threads and replies with their authors. |
| Certificate codes | CSV | Every issued code with its course, date and current state — and they keep verifying. |
Not in the export: another school's anything, platform-level analytics that were never yours, and payment credentials held by the payment provider rather than by Coursio.
Request an export
An owner requests it from school settings. The job runs against one school, reports its own state, and produces a file you download — no support ticket, no negotiation on the way out.
Shown here as the surface an owner uses. Both actions run against one specific school, so they are inactive on this public page — a school owner performs them from school settings.
Export states this surface renders
- QueuedWaiting for a worker
- ProcessingRunning now
- ReadyDownload available
- FailedReason shown · retry
- A school that has never exported shows “No exports yet”. A failed read of the history says so rather than rendering an empty list as if nothing had ever been requested.
Where the platform ends
Coursio depends on a payment provider, a video provider and an email provider. Three of those relationships are not fully decided, and pretending otherwise would put a number on this page that no one measured.
Inside the product, an unconfigured provider is a visible, actionable state on the surface that needs it — never a silent failure and never a green tick borrowed from a different school.
See how this reads on the plansPayments, merchant and tax
Launch-country dependent- Settled
- Checkout, order states and the rule that access is written from a verified payment event.
- Open
- Who is merchant of record, and who is responsible for sales tax or VAT, by launch country.
Until that resolves, the checkout and offer surfaces name the actor rather than assuming it, and no page here claims Coursio handles your tax.
Video provider, runtime and allowances
Decision pending- Settled
- Managed upload with honest asset states — Processing, Ready or Failed — and signed playback per enrollment.
- Open
- Which provider, what transcode runtime to expect, and how much storage and streaming each plan includes.
Every allowance on the pricing page reads Configuration required after provider PoC. No plan claims unlimited video, unlimited storage or a guaranteed processing time.
Lifecycle email
Decision pending- Settled
- Which lifecycle emails exist, who they belong to, and that the list never leaves the school.
- Open
- Sending provider, per-plan volume, and whether a school may bring its own sending domain at launch.
The email surface shows a provider state before it shows a send button, so nobody schedules a campaign against an unconfigured sender.
Provider status inside the app
While the status loads, the panel shows placeholder rows and no verdict. A school that has configured nothing yet reads Action required with the setup route attached. If the status check itself fails, the panel says the check failed — it does not fall back to Ready.
Access is written by an event, not by a page
Landing on a success page is not access. Enrollment is written when a payment callback verifies, and playback is signed against that enrollment — which is why a refund closes a course and a forwarded link opens nothing.
Payment callbacks — sample school
Including the one that was rejected.
checkout.session.completed
Signature verifiedEnrollment written for Daniel Chen on Editorial Systems for Creators. Playback becomes available at that moment, not before.
charge.refunded
Access revokedEnrollment moved to Revoked the same day. Issued certificates are not deleted — they resolve to Revoked with their date.
checkout.session.completed
Rejected · bad signatureNo enrollment written, nothing unlocked, the attempt kept in the log. An unverifiable callback is discarded, never trusted because it looked plausible.
checkout.session.completed
Retrying deliveryA duplicate of an event already applied does not create a second enrollment or a second charge against the school's ledger.
While the ledger loads it shows placeholder rows; a school with no orders reads “No payment events yet”; a failed read says so and offers a retry. It never renders an empty ledger as evidence that nothing went wrong.
Playback controls
- Signed per enrollmentThe URL is minted for one learner and one lesson, and it expires. It is not a public file with a hard-to-guess name.
- Expires with accessRevocation, refund or the end of an access term closes playback the same day, without waiting for a cache to age out.
- Sharing a link achieves nothingA forwarded URL fails for anyone who is not the enrolled learner it was signed for.
- Signed playback is not DRMIt stops link sharing and stale access. It does not stop a determined learner from recording their own screen, and Coursio will not claim that it does.
Credentials
The proof says less than you expect, on purpose
A public certificate page has to convince a stranger without exposing the learner. It carries what a verifier needs and nothing else, and it keeps resolving after the enrollment, the course or the tenant has moved on.
Public on the proof
- Course title
- Issuing school
- Issue date
- Current state — Valid or Revoked
Never public
- The learner's email address
- Their quiz answers or attempt history
- What they paid, and when
- Any other course they are enrolled in
Open decision
Decision pendingWho holds the signing key
Certificates are issued by the school and verified through Coursio. Whether the key that signs them is held by the platform, by each school, or by both under an escrow arrangement is not settled.
It matters, so it is not being decided quietly: platform custody makes verification simple but ties continuity to Coursio; school custody moves that continuity to you and moves the key-loss problem with it.
Until it is settled, issuance commits with signature_algorithm unsigned and no signing key configured, the certificate surfaces label that custody state, and this page does not describe a signature guarantee that has not been implemented.
Inactive because no sample certificate has been issued on this instance. A proof link that resolves to nothing would be exactly the kind of claim this page refuses to make.
What a verifier sees when something is wrong
- Unknown code — “No certificate matches this code.” Never a blank page, never a default success.
- Revoked — the state and its date, so a stale copy in someone's inbox cannot outrank the record.
- Service unreachable — “We could not check this code right now.” An unreachable service never reads as invalid, and never as valid.
Privacy and access, in specifics
Two areas where a vague commitment is worse than none. These are the concrete rules the product is built to; where a claim would need a certification Coursio does not hold, it is not made.
Coursio holds no third-party security or accessibility certification, and this page does not imply one. What follows is what the product does.
What learner data does a school hold?
Name, email, enrollments, per-lesson progress, quiz attempts, orders and community posts — scoped to that one school. A learner in two schools has two separate records, even with the same email address.
Who can read a learner's progress?
The school owner, and an instructor for the courses they are assigned to. Not other learners, not another school, and not the public proof page.
Can a learner be deleted?
Yes, by the school that holds the record. Deletion removes the learner and their personal data; issued certificate codes keep resolving to course, school and date, which is the point of a portable proof.
Is the interface keyboard and screen-reader operable?
It is built to be: visible focus on every control, tap targets of at least 44 by 44 pixels, dialogs that trap and restore focus, tables with real headers, and status that is never signalled by colour alone.
Does the product respect reduced motion?
Yes. With reduced motion on, animation is switched off and the finished state is rendered directly — including the chain at the top of this page. Content never depends on an animation having played.
What happens with JavaScript disabled?
Public pages stay readable — nothing is hidden behind a reveal that only a script can trigger. Interactive app surfaces need JavaScript, and say so rather than rendering an empty shell.
Check it before you trust it.
Open a school, sell yourself one offer, refund it, and watch the course close. Then export the tenant and verify the certificate code from the file. Every claim above is testable in an hour.
- Refund a test orderThe enrollment should read Revoked and playback should stop the same day.
- Forward a lesson URLIn a signed-out browser it should open nothing at all.
- Export and read the fileCourse structure, enrollments, progress and certificate codes should all be in it.
- Verify a code from the exportIt should still resolve — that is what continuity means here.