Long Term Access
What it solves
The standard API is built around a user who is present: you hold an access token for one user, it lives an hour, and you refresh it as needed.
That model breaks down when a server-side service follows its users over months. Keeping 500 users readable means storing 500 refresh tokens, refreshing each of them on a schedule, handling rotation — and losing a user for good as soon as one of those tokens expires.
Long term access replaces that with a single durable token per user. Your service stores it and reads that user's data whenever it needs to, authenticating only as itself.
| Standard mode | Long term access | |
|---|---|---|
| Credential per user | Refresh token, expires | Long term token, until revoked |
| Keeping it alive | Refresh on a schedule, handle rotation | Nothing |
| User must sign in again | Yes, when the refresh token expires | No |
| User can revoke | On logout / token revocation | Any time, from their account page |
| Endpoints | The public API | The same public API |
Requesting access
The standard per-user mode remains the one to reach for. It covers almost every integration, and if your feature can be built with it, that is what we will point you to rather than opening this one.
It is also not a key to the whole API. Only a deliberately small set of endpoints accepts a long term access token — see Reading data for the current list. Everything else stays reachable with a regular user token only, and being granted this mode does not change that. If what you need is not in that list, this is not the answer to your problem.
Long term access hands your service long-lived, unattended access to the personal data of many people. We open it deliberately, not on demand, and we need to understand your project before we do.
Reach us on
Discordor through the contact form.
Describe your request precisely — a vague one will be turned down rather than chased up.
Your project
- What your service does, in full: what it is for, who runs it, whether it is free or paid, open source or not, and where it is hosted.
- Who your users are, and roughly how many of them you expect to enroll.
- How your users reach it — a website, a mobile app, a home automation setup, a research protocol…
Your use of the DiapStash API
- Which endpoints you already call, and how often.
- Why the standard per-user mode does not fit — be concrete: what breaks, or what you cannot build without long term access. This is the claim we weigh most heavily, and the one most requests fail on.
- Which long term scopes you need, and what each one is for. Asking for the narrowest set that makes your feature work makes the request much easier to grant.
- How often you will read each enrolled user.
What you do with the data
This is the part we read most carefully. Our users are trusting you with intimate, personal data.
- What you store, where it is hosted, and for how long.
- How it is secured: encryption at rest and in transit, who on your side can access it, and how long term access tokens themselves are protected.
- Who else sees it: any third party, subprocessor, or analytics provider it passes through.
- That you do not resell, trade, or share the data, and that you do not use it to train models or build advertising profiles. We will ask you to state this explicitly.
- What happens when a user revokes, or deletes their account on your side: how their data is deleted, and within what delay.
- A link to your privacy policy, covering the above.
Requirements your client must meet
- It must be a confidential backend client — an application type of
API / Server, with a client secret. A Javascript Web App or a native app can never be granted this mode: its secret cannot be kept. - It must be able to keep long term access tokens secret, at rest, on your own servers.
Once we open the mode on your client, a Long term access section appears on it in your API access tab. You pick the long term scopes there yourself, and can take one back at any time by unticking it.
Scopes
Long term access uses its own scope family, separate from the regular cloud-sync.* scopes. Asking
for one of them in an ordinary sign-in is what turns it into a long term enrollment.
| Scope | Description |
|---|---|
cloud-sync.permanent.latest-change | Read the latest change of enrolled users |
cloud-sync.permanent.stats | Read aggregated statistics of enrolled users |
Users see these on the consent screen with an explicit warning that the access survives their session.
invalid_scope. That refusal is the gate — there is nothing else to
configure on your side.Enrolling a user
Enrollment happens once per user, against account.diapstash.com, in two steps.
1. Get the user's consent
An ordinary authorization code flow. The only difference from a regular sign-in is the scopes you ask for:
https://account.diapstash.com/oidc/auth?
client_id=YOUR_CLIENT_ID
&redirect_uri=YOUR_REDIRECT_URI
&response_type=code
&scope=openid cloud-sync.permanent.latest-change cloud-sync.permanent.stats
Exchange the code at the token endpoint as usual, and keep the resulting access token for the next step. It is short-lived, so do this right away.
2. Exchange it for a long term access token
POST https://account.diapstash.com/api/long-term-access/tokens
Authorization: Bearer <THE USER ACCESS TOKEN FROM STEP 1>
{
"token": "dspa_a1b2c3d4e5f60718293a4b5c_XSyR...",
"scopes": ["cloud-sync.permanent.latest-change", "cloud-sync.permanent.stats"]
}
That access token is the whole authorization: it says which user consented, to which client, and for which scopes. The long term access token inherits exactly those scopes — never more.
Re-enrolling the same user rotates their token: the previous one stops working immediately.
Reading data
Long term access does not add endpoints. It adds a second way to authenticate on the ordinary
ones: the routes below accept a cloud-sync.permanent.* scope and work in both modes, returning
the exact same payload.
regular Authorization: Bearer <USER ACCESS TOKEN>
DS-API-CLIENT-ID: <CLIENT ID>
long term Authorization: Bearer <LONG TERM TOKEN>.<YOUR CLIENT SECRET>
The long term credential is a single bearer token: the user's long term access token, a dot, then your
client secret. Its dspa_ prefix is what tells it apart from a user token.
curl -H "Authorization: Bearer dspa_a1b2c3d4e5f60718293a4b5c_XSyR....YOUR_CLIENT_SECRET" \
https://api.diapstash.com/api/v1/history/latest-change
Both halves are needed. Our database only stores a hash of the long term access token, and your client secret on its own names no user.
| Endpoint | Long term scope | Regular scope |
|---|---|---|
GET /api/v1/history/latest-change | cloud-sync.permanent.latest-change | cloud-sync.history |
GET /api/v1/history/stats | cloud-sync.permanent.stats | cloud-sync.history |
Everything else — the paginated /history/changes and /history/accidents, stocks, types — stays
reachable only with a regular user token. Long term access deliberately covers the two reads a
server-side service needs to follow a user over time, not the whole API.
Error responses
A long term call fails as a whole; there is no per-user status to read.
| Status | Meaning | What to do |
|---|---|---|
401 | Credential unknown, malformed, or the client secret does not match | Check your configuration — this is not necessarily a revocation |
401 PermanentAccessRevoked | The access existed and has been revoked | Delete your copy of the token; it will never work again |
401 NoCloudSyncLinked | The account has no Cloud Sync linked | Ask the user to link it in the app |
403 CloudSyncInactive | Cloud Sync silent for over 90 days | Keep the token — access resumes on its own |
403 | Neither your client nor the user granted the scope you asked for | Re-enroll asking for that scope |
404 | Nothing recorded for that user (current change only) | Nothing; the access is fine |
401 covers an unknown token and a wrong client secret alike, on purpose: we do not confirm
whether a token ever existed to anyone who cannot already prove it. You only get
PermanentAccessRevoked when both halves of your credential are correct — which is why it is safe to
tell you. We never say who revoked it.403 CloudSyncInactive is not a revocation. A user who stops syncing for a few months and comes
back keeps working with the same token — do not delete it.Rate limits
Per client, per hour, returned in the standard RateLimit response headers — the same budget as the
rest of the public API. Your client is identified by the credential itself, so DS-API-CLIENT-ID is
not needed in long term mode.
Revoking
The user
Users see every service holding a long term access in the Connected services tab of
their account, with the scopes granted, when it was granted, and when
you last used it. One click revokes it, and your very next call returns PermanentAccessRevoked.
Your service
Drop a token you no longer need:
DELETE https://account.diapstash.com/api/long-term-access/tokens
Authorization: Bearer <LONG TERM TOKEN>.<YOUR CLIENT SECRET>
The credential names the token to drop, so there is nothing to send in the body. Always answers
204, whether or not the token existed.
Us
We can withdraw the mode from your client. Every token you hold stops working at once. We do this if the feature is used outside the scope of your request, or on abuse reports.
Handling the tokens
- Encrypt them at rest. They are equivalent to passwords, not to identifiers.
- Never log them, and never put them in a URL — they belong in the
Authorizationheader, which most logging setups already redact. - Never expose them to a browser or ship them to a mobile app.
- Delete your copy as soon as a token comes back
PermanentAccessRevoked. A plain401is more likely a configuration problem than a revocation — check before discarding anything. - Delete a user's token when they delete their account on your side. Do not wait for them to also find the DiapStash account page.
Deleting a DiapStash account revokes every long term access on it.
Support
Questions or issues: Discord