billing

POST /v1/trials/winback

Take the one-time 7-day extension — the ended trial runs again for 7 days.

All billing endpoints

All developer docs →

Authentication

Send an API key as a bearer token. The endpoint checks billing.view; a key without it is refused with 403, not 404.

Where your organisation id goes

This endpoint takes org_id as a field in the JSON body.

Your organisation id is on the API keys screen in your dashboard, beside the key itself. It is the same id in every call you make.

Try it

Replace anything in angle brackets with your own values, and the key placeholder with a key from your dashboard.

curl -X POST https://api.zinndigital.com/v1/trials/winback \
  -H "Authorization: Bearer zdk_live_…" \
  -H "Content-Type: application/json" \
  -d '{  }'

Signed in? The API console in your dashboard fills in your real organisation id and your own key, and runs the request against the live API so you can see the actual response. Open this endpoint in the API console

Details

s1014 L55. The SAME trial row runs again until now + 7 days: same product line, same site limit, same plan; nothing is upgraded and nothing is charged. Sites the trial's end took offline come back, unless another enforcement (malware, abuse) holds them. Only a signed-in person may take it — not an API key and not a staff impersonation session (refusal.trial.winback.personOnly). Refusals: refusal.trial.winback.alreadyUsed (this person or this account already took it), refusal.trial.winback.notOffered. Audit-logged as trial.winback_extended.

Request body

NameTypeRequiredWhat it is
org_idstringNoRequired when the caller bills for several organizations.

Response

NameTypeRequiredWhat it is
idstringYes—
org_idstringYes—
statusstring<active, expired, converted, canceled, switched>Yes—
product_linestringYesThe line's CODE, not its display name — the dashboard renders the label from its own catalogue, so prose here would be a second, untranslated source of that word on the screen.
max_sitesintegerYes—
started_atstringYes—
ends_atstringYes—
auto_convert_opt_inbooleanNoWhether the customer agreed at the start that this may become a paid subscription when the period ends. Captured per trial rather than read from the template at expiry, so…
days_remainingintegerNoWhole days until ends_at, rounded UP and floored at zero. Computed on the server on purpose: a client doing (ends_at - Date.now()) measures the device clock, so a laptop a…
upgradeTrialUpgradeOfferNoThe plan this trial invites the customer to buy, priced in their own currency (X-Zinn-Currency, falling back to the org default). ⛔ null when the template names no target or…
switch_deadlinestringNos1014 L58 (owner 2026-10-16). Until when this trial may still be switched to another product (POST /v1/trials/{trial_id}/switch): its first three days. null when it cannot be…
planobjectNos1014 L70. The plan this trial was started for (the one the customer clicked) and the application it installs, so the create-site form opens on that application — a "Moodle Pro"…

Errors this endpoint can return

401 · 403 · 422