API authentication and keys
How API keys work: creating them, scopes, expiry, revoking, and how they differ from your TJA_ license key.
On this page (10)
Every authenticated call to /api/v1 carries an API key. A key stands in for your account the way a browser session does, but it is meant for scripts: no cookies, no sign-in page, no expiry unless you ask for one.
Keys are created and revoked in Account β Connections, behind the Create API key button in the API keys section of that tab.
Sending the key#
Preferred β a bearer token:
curl -s https://threejsassets.com/api/v1/me \
-H "Authorization: Bearer tja_live_β¦"Equivalent β the X-API-Key alias, for clients that reserve Authorization for something else:
curl -s https://threejsassets.com/api/v1/me \
-H "X-API-Key: tja_live_β¦"If both are present, the Authorization header wins. Send the key as a header only: never in a query string, never in client-side JavaScript, never committed to a repository.
An API key is not your TJA_ license key#
These are two different credentials and they are not interchangeable. This is the single most common mix-up, so it is worth being blunt about:
| API key | License key | |
|---|---|---|
| Looks like | tja_live_β¦ | TJA_XXXX-XXXX-β¦ |
| Identifies | your account | one purchase |
| Used with | /api/v1/*, as a header | /api/download, in the JSON body |
| Created by | you, in Connections | issued automatically with an order |
| How many | up to 10 at a time | one per order |
Passing a TJA_ license key as Authorization: Bearer does not work. It is rejected before any lookup happens and you get:
{
"error": {
"code": "invalid_api_key",
"message": "That API key isn't valid. Check it was copied in full, or create a new one in your account's Connections tab.",
"request_id": "5f3c9a10-2d6b-4b2e-9f77-1c0a8de41b52"
}
}If you see invalid_api_key and your credential starts with TJA_, you are on the wrong endpoint: license keys belong to the older /api/download route described in Downloading your packs. The reverse also holds β an API key is not accepted there.
The API never returns a license key in full. /v1/orders shows a masked preview only.
The key is shown exactly once#
When you create a key, the full value appears in the create dialog, with a Copy button next to it. It is stored only as a hash, so nobody β including support β can display it again once you close that dialog.
If you lose a key, revoke it and create a replacement. There is no "show key" and no recovery.
A key looks like this:
tja_live_9f2cKp3xQm7RvL0aZs4Td8Bn1YhE6Wug_4kR7pq
βββββ¬ββββββββββββββββββββ¬ββββββββββββββ ββββ¬βββ
prefix random secret checksumThe tja_live_ prefix makes keys easy to spot in a config file or a secret scanner. The trailing checksum catches a truncated copy-paste before anything else is checked.
Scopes#
Each key carries a set of scopes. Both are selected by default, which is what most people want; narrowing them is how you make a key that is worthless to a thief.
| Scope | Grants |
|---|---|
catalog:read | /v1/me, /v1/packs, /v1/assets, /v1/orders, /v1/products, /v1/products/:slug |
downloads:read | /v1/packs/:slug/download, /v1/assets/:slug/download, /v1/products/:slug/download, and all three icon routes β /v1/icons/:name, /v1/icons/:name/download, /v1/icons/library |
/v1/icons/:name is a metadata route that needs the download scope, which looks odd until you see why: its response can carry the icon's SVG, and an SVG is the artwork. Delivering bytes is what downloads:read means everywhere else, so it means it there too. For metadata alone, the public /v1/catalog/icons needs no key at all.
A key with only catalog:read can inventory your library but cannot pull a single byte of a file. Calling a download endpoint with it returns 403 insufficient_scope:
{
"error": {
"code": "insufficient_scope",
"message": "This key is missing the \"downloads:read\" scope. Create a new key with it enabled.",
"request_id": "5f3c9a10-2d6b-4b2e-9f77-1c0a8de41b52"
}
}Scopes cannot be edited after creation. To change them, create a new key and revoke the old one.
Expiry#
When you create a key you choose how long it lives:
- Never expires (the default)
- 90 days
- 1 year
A key with an expiry stops working the moment it passes β calls return 401 expired_api_key. Fourteen days before that happens we email you, so a build server does not fail at 3am with no warning.
Pick a TTL for keys you hand to someone else or paste into a third-party CI system. Pick "never" for a key you control and can revoke yourself.
Revoking a key#
Open Account β Connections and select Revoke next to the key. Revocation is immediate and permanent; the next call with that key returns 401 revoked_api_key.
Revoke a key when:
- it has been committed to a repository or pasted into a chat;
- a machine or contractor no longer needs access;
- the Connections tab's Recent API downloads list shows a download you did not make.
Revoking a key never affects your purchases, your license keys, or your other keys. You can always revoke, even while API access is otherwise unavailable to your account.
Limits and good practice#
- Up to 10 active keys per account. Revoke one to make room for another.
- One key per machine or job, named after it. That way revoking is surgical, and
/v1/metells you which one is calling. - Store keys in a secret manager or environment variable, not in source.
TJA_API_KEYis the name our examples use. - Rotate by overlap: create the new key, deploy it, then revoke the old one.
Who can use the API#
API access requires a purchase β buy any pack or lifetime access and the Connections tab opens up. If access is unavailable for your account you will see a notice explaining why in the Connections tab, and calls return 403 api_disabled or 403 not_eligible. Existing keys are left intact in that case; they simply fail until access returns.
Partner access#
Listing our catalog on your own site needs no key and no account at all β the public /v1/catalog/* endpoints are open, as the endpoint reference explains. What listings do need is a visible credit: "by ThreeJS Assets" on each card is the style we prefer, and a single "Assets by ThreeJS Assets" per page also works β both are shown, with copy-paste snippets, on threejsassets.com/partner. A key only enters the picture when you want to download or import actual model files, which live on the authenticated /v1/assets routes.
If you are on a free account and want that, request access through the form on threejsassets.com/partner. Approval is manual β a person reads every request and replies by email, so there is no instant grant. Once you are approved, the Connections tab opens up and you create keys the normal way; a free account's keys cover free-tier files only.
Next steps#
Ask us directly β we answer support mail ourselves.