Skip to content

Redeem a partner access code

POST
/api/billing/access-code/redeem/
curl --request POST \
--url http://localhost:8000/api/billing/access-code/redeem/ \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "code": "ACME-7KQ4MX" }'

Owner-only. Puts the caller’s active team on the plan the code’s batch grants (e.g. Starter, 25 analyses, 183 days), with no card and no Stripe subscription. When the term ends the team returns to Free; its account and reports stay.

Errors (detail)

  • 400 invalid — no such code, or it was revoked.
  • 400 expired — the code’s batch is closed or past its redeem-by date.
  • 400 email_not_verified — verify the sign-in email first.
  • 400 wrong_domain — the batch only accepts one email domain (e.g. alaska.edu); sign up with that address.
  • 400 unavailable — the code’s plan can’t be granted right now; nothing was spent. Contact support.
  • 409 already_used — the code was redeemed before.
  • 409 already_redeemed — this team’s previous code is still running.
  • 409 already_paid — the team is on a paid or complimentary plan already.
  • 403 — the caller does not own their active team.

Throttled per user.

object
code
required
string
>= 1 characters <= 32 characters

Examples

ExampleRedeem
{
"code": "ACME-7KQ4MX"
}
Media typeapplication/json
object
plan
required

Name of the granted plan.

string
role
required

Role of the granted plan (starter, pro, …); the key a client translates the plan name by.

string
sessions
required

Analyses for the whole term; they do not reset monthly.

integer
access_end
required

When the team returns to the Free plan.

string format: date-time

Examples

ExampleAccessGranted

Access granted

{
"plan": "Starter",
"role": "starter",
"sessions": 25,
"access_end": "2027-05-19T10:00:00Z"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string

Examples

ExampleWrongEmailDomain

Wrong email domain

{
"detail": "wrong_domain"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string

Example generated

{
"detail": "example"
}
Media typeapplication/json
object
detail
required

Human-readable message, or a stable machine code for the cases a client branches on. The standard envelope for 400 (validation — a field-keyed object may appear instead), 401 (missing / invalid credentials), 403 (authenticated but not permitted), and 404 (absent — cross-team records are collapsed to 404 so the API never leaks the existence of another team’s data).

string

Example generated

{
"detail": "example"
}
Media typeapplication/json
object
detail
required

409 — the request conflicts with current state. detail is a stable code (e.g. reanalyze_in_flight, already_on_plan, email_in_use). Some 409s carry extra context fields alongside detail; those are documented on the specific endpoint that emits them.

string

Examples

ExampleCodeAlreadyUsed

Code already used

{
"detail": "already_used"
}
Media typeapplication/json
object
detail
required

429 — rate limit exceeded. Honour the Retry-After response header (seconds to wait) before retrying; it is sent on every 429.

string

Example generated

{
"detail": "example"
}