Short-lived tokens
Tokens are small, time-boxed credentials you hand to the SDK instead of a permanent API key.
Property | Description |
---|---|
Format | sh_<32 hex chars> |
Carry | Everything the SDK needs - licence, limits, optional remote config |
TTL | 60 - 86 400 seconds (default 3600 s) |
Scope | Only allows initializing the SDK |
Why prefer tokens?
- Leak resistance - a captured token dies quickly, your permanent key stays safe.
- Granular limits - set max measurements or single-device lock.
- Dynamic config - You can dynamically construct SDK configuration on-demand for each individual SDK usage.
End-points
Method | Path | Purpose |
---|---|---|
POST | /v1/token | Create one token |
POST | /v1/tokens | Create many (up to 1000) in one call |
Both require the tokens:generate
scope.
Request body (single-token)
Field | Type | Required | Notes |
---|---|---|---|
license_id | int | No | Omit to use first active licence |
expires_in | int | No | 60 - 86 400 (seconds), default 3600 |
max_measurements | int | No | Hard-cap per token |
single_device | bool | No | Lock to first device |
sdk_config_id | int | No | Embed an existing Remote Config |
sdk_config_inline | object | No | Full JSON config (mutually exclusive with above) |
See the OpenAPI reference for the exact schema.
Quick example - one-hour, single-device token
curl -X POST https://api.shen.ai/v1/token \
-H "Authorization: Bearer $SHENAI_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{"expires_in":3600,"single_device":true}'
Response
{
"token": "sh_b71ef965c4c4468b9eab8c646f6f6d16",
"expires_at": "2025-07-15T12:00:00Z"
}
Quick example - five tokens in bulk
curl -X POST https://api.shen.ai/v1/tokens \
-H "Authorization: Bearer $SHENAI_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{ "count": 5, "expires_in": 1800 }'
Returns an array of five objects identical to the single-token response.
Using the token in the SDK
Any Shen.AI SDK constructor accepts a token exactly where you used to pass the permanent key.
// Web SDK
shenaiSDK.initialize("sh_b71ef965c4c4468b9eab8c646f6f6d16");
// Android
shenaiSDKHandler.initialize(this, "sh_b71ef965c4c4468b9eab8c646f6f6d16");
No other code changes are needed.
Best practices
Do | Why |
---|---|
Store the Admin Credential in an env variable | Never check secrets into git |
Use single_device: true whenever feasible | Prevents key-sharing across devices |
Keep TTL short (≤ 1 h) for Web SDK | Limits impact of a leak |
Use longer TTL for mobile SDKs if you expect offline usage | Ensures the SDK can continue working even if the device has no internet connection |
Error catalogue
HTTP status | Error code | Typical cause |
---|---|---|
400 | BAD_REQUEST | Missing or malformed JSON |
401 | UNAUTHORIZED | No / bad Authorization header |
403 | FORBIDDEN | Admin Credential lacks tokens:generate |
500 | SERVER_ERROR | Unexpected backend issue |
Tokens cannot currently be revoked individually.
Design for short TTLs or rotate the Admin Credential if immediate revocation is needed.
FAQ
Can I refresh a token on the device?
No. The device must ask your backend for a fresh token.
Does using tokens change billing?
No - measurements count the same way they do with permanent keys.
What if max_measurements
is reached before expires_at
?
The SDK treats the token as expired and will refuse to initialise.
What happens when during an SDK session max_measurements
is reached?
In the embedded SDK’s UI, the equivalent of enableStartAfterSuccess
will be set to false
, and the user won’t see the “Measure again” button on screens after completing the measurement. If you use your own UI, there will be no effect and you will still be able to start new measurements.
What if a token expires while the SDK is running?
The SDK will continue to work until it’s deinitialized.
Is it possible that more than one measurement is made with a token that set max_measurements = 1
?
Yes, if multiple SDK instances are initialized with the same token before starting any measurements, they will not be prevented from starting the measurement. To prevent that scenario, use single_device: true
to limit usage to a single device.