Skip to content

Versioning

Note: The Teachify Admin API is currently under development and not yet available for public use. This documentation is provided for preview purposes only.

The Admin API is versioned by release date. Additive changes (new fields, arguments, types and enum values) ship continuously to every version. Breaking changes are grouped into dated releases that a client opts into.

The field tables in these docs describe the 2027-01-01 release. Timestamps are shown as Int, except fields already documented as BigInt. Under 2027-04-01, those Int timestamps become BigInt strings. See Migrating to 2027-04-01.

Send the date of the release your integration was built against in the API-Version header:

Terminal window
curl \
-X POST \
-H "Content-Type: application/json" \
-H "X-Teachify-API-Key: <Your API Key>" \
-H "API-Version: 2027-01-01" \
--data '{ "query": "{ courses { nodes { id name } } }" }' \
https://teachify.io/admin/graphql

The API resolves the header as follows. A credential is the API key, the OAuth application (its creation date, not the access token’s), or the App Installation that authenticates the request.

SituationSchema you get
Header names a release dateThat release
Header names a date between two releasesThe release in effect on that date
Header names a date later than the newest releaseThe newest release
Header names a date older than every releaseThe baseline (pre-versioning) schema
No header, credential created on or after a release dateThe release in effect when the credential was created (pinned)
No header, credential older than every releaseThe baseline schema
Header present but empty or whitespace-onlyTreated as no header
Header is not YYYY-MM-DD400 with extensions.code set to INVALID_API_VERSION

Any valid YYYY-MM-DD date is accepted, including a future date. To test an upcoming release before it takes effect, send its date now, for example API-Version: 2027-04-01.

The response echoes the version the request was resolved with in an API-Version header: the header value you sent, or the pinned release when you sent none. The response also lists API-Version in Vary. Cross-origin browser clients can read the API-Version response header. A request with no header and no pinned release gets no API-Version response header.

Pinning keeps an integration on the schema it was built against without sending the header. Sending the header on every request is still recommended, and it is required to move to a newer release.

A header value that is not a YYYY-MM-DD date is rejected with HTTP 400:

{
"errors": [
{
"message": "\"latest\" is not a valid API version (expected YYYY-MM-DD)",
"extensions": {
"code": "INVALID_API_VERSION"
}
}
]
}

When a request selects a field that a later release removes, the response carries an API-Deprecated header. It names each such field and the release that removes it:

API-Deprecated: CurriculumPlan.symbol; removed=2027-01-01

Each entry is Type.field; removed=YYYY-MM-DD. Several entries are separated by commas, and each field appears once. The header is absent when the request selects no field scheduled for removal, and when the request fails validation. Cross-origin browser clients can read the API-Deprecated response header.

  • Breaking changes are batched into at most one release per quarter. A release is dated the first day of the quarter: YYYY-01-01, YYYY-04-01, YYYY-07-01 or YYYY-10-01.
  • A field or type scheduled for removal is marked @deprecated, with the release date in its reason, at least three months before that date.
  • Every release stays available for at least twelve months after the next release ships. After that, its definitions may be folded into the baseline. The schedule is announced in the changelog before it happens.
ReleaseChanges
2027-01-01CurriculumPlan.symbol is removed. Use currencySymbol.
2027-04-01Every Unix-timestamp field, argument and filter typed Int / IntOperator moves to BigInt / BigIntOperator, so dates after 2038-01-19 encode. Timestamps already typed BigInt keep their type. See Migrating to 2027-04-01.
  • BigInt is serialized as a JSON string, for example "1893456000". Parse it before you compare or sort it. As strings, "999" > "1000".
  • Timestamp arguments and filters accept an integer as a JSON number or a numeric string. Any other number is rejected with must be an integer, including 1700000000.0. Values must fall between 0001-01-01 and 9999-12-31 UTC.
  • Update variable declarations. A $since: Int or $filter: IntOperator variable fails validation against a BigInt / BigIntOperator argument. Inline literals such as since: 1700000000 keep working. If you use code generation, add a BigInt scalar mapping. Generated types change from number to string.
  • Earlier releases keep Int. On an earlier release, a timestamp outside the Int range is clamped to 2147483647 (2038-01-19) or -2147483648 (1901-12-13) instead of failing the query. Do not write a timestamp read on an earlier release back unchanged: it moves a later date to 2038. A clamped value also does not match an eq filter, and earlier releases cannot send a timestamp after 2038.
  • On every release, timestamps that were already BigInt now get the same integer and 0001–9999 checks. This covers the BigIntOperator filters (updatedAt on payments, courses and membership plans; createdAt on reviews) and the coupon, event, assignment and curriculum plan inputs. A fraction or an out-of-range value is now a validation error instead of a failed request or a silently stored value.