Install our app for a better experience!

Access Duration, Renewals & Expiry

Access Duration, Renewals & Expiry

Every course you grant through the API has an access window. This page explains how that window is set, what the student experiences before and after it ends, and how to renew or extend it. All dates below come from real API responses.


How the window is set

Date in the response How it is worked out
start_date The day of the call. Access starts immediately.
end_date start_date plus the number of months, in calendar months. 17 Sep 2026 + 6 months = 17 Mar 2027.
grace_period_end end_date plus your organization's grace days. This is the last day the student can still practise.

How many months? The first of these that applies:

  1. tenure_months in the call (1–120).
  2. For a course chosen with course_ids: that course's own default duration (courses[].default_access_months).
  3. Your organization's default (provisioning_defaults.default_access_months from GET /organization/).

Grace days come from your organization's settings (provisioning_defaults.grace_period_days). With a grace of 0, grace_period_end equals end_date.


The timeline, with real dates

Jane was onboarded on 17 Sep 2026 with "tenure_months": 6, in an organization with 30 grace days:

17 Sep 2026            17 Mar 2027                   16 Apr 2027
start_date ───────────▶ end_date ──── grace period ──▶ grace_period_end ──▶ access removed
   full access              full access continues            last day            from the next day
When What the student experiences status has_access
Up to end_date Full access to the course. active true
After end_date, up to grace_period_end Still full access. grace_period true
After grace_period_end Can still sign in and see all past results. Cannot start a new test. expired false
  • A test already in progress when access ends can always be finished, and the result is delivered.
  • Emails to students only ever mention end_date, never the grace period.
  • If your organization has access reminder emails switched on, the student is reminded before access ends.
  • The platform checks dates daily, so status changes shortly after a date passes. The dates and has_access in the API always reflect the dates, whatever the stored status says at that moment.

Renewing after access ended

Send the same call again, with the new duration. If the course's end_date has passed (including during the grace period, or after access was removed), the same enrolment gets a fresh window from today. No duplicate is created, and the student keeps all their past results.

{ "email": "ali@example.com", "first_name": "Ali", "course_ids": [371],
  "tenure_months": 6, "external_ref": "wc_order_1600" }

Ali's access had ended 45 days earlier. Shortened response:

{
  "status": "success",
  "enrollments": [
    { "course_id": 371, "course_name": "IELTS Weekend Batch", "action": "reactivated",
      "status": "active", "start_date": "2026-09-17", "end_date": "2027-03-17",
      "grace_period_end": "2027-04-16", "has_access": true, "starter_tests_assigned": 1 }
  ],
  "email": { "status": "sent", "type": "welcome", "detail": "" }
}

Extending while access is still running

A plain repeat call does not add time to a course that is still running. That is what makes retries safe. To add time, say so explicitly with extend_access and give the purchase a reference:

{ "email": "jane@example.com", "first_name": "Jane", "courses": ["ielts"],
  "tenure_months": 3, "extend_access": true, "external_ref": "wc_order_1500" }

Jane's IELTS access was due to end on 17 Mar 2027. Shortened response:

{
  "status": "success",
  "enrollments": [
    { "course_type": "ielts", "action": "extended", "status": "active",
      "start_date": "2026-09-17", "end_date": "2027-06-17", "grace_period_end": "2027-07-17" }
  ]
}

The three months were added to the current end date, not to today. Sending the same call again (for example a retried webhook) changes nothing:

{ "status": "already_provisioned",
  "enrollments": [ { "action": "unchanged", "end_date": "2027-06-17",
                     "note": "already_extended_for_external_ref" } ] }

Why external_ref is required: each reference extends a given course at most once. Use your order or payment id, so a genuine second purchase (new id) extends again and a retry (same id) does not.


What each action means

action What the call did to this course
created New enrolment with a fresh window.
reactivated The window had ended; the same enrolment now has a fresh window from today.
extended Time was added to a window that was still running (extend_access).
unchanged The window is still running and nothing was requested, so nothing changed.
skipped Left alone on purpose. skipped_reason: "suspended" means an admin suspended this student.

already_enrolled is true for unchanged and skipped, and false otherwise.


Statuses you may see

status Meaning
active Inside the access window.
grace_period After end_date, still has access until grace_period_end.
pending Scheduled to start later (only set from inside the platform).
expired Access removed after the grace period. Renew with another call.
suspended An admin suspended the student. The API never lifts a suspension; do it in the platform.
dropped / completed Ended from inside the platform. Renew with another call.