Obtaining and refreshing an access token
Access token
Refresh token
OAuth
Expiry
Who this article is for
For developers handling the access tokens used to call the ReceiptRoller API.
For developers handling the access tokens used to call the ReceiptRoller API.
Call the API by attaching the access token obtained via the OAuth authorization code flow to the Authorization: Bearer ... header. The access token has an expiry; before it expires, refresh it with the refresh token.
Guideline expiries
| Token | Expiry | Purpose |
|---|---|---|
| Access token | 1 hour | API calls |
| Refresh token | 90 days | Refreshing the access token |
| Authorization code | 10 minutes (one-time) | Initial token retrieval |
Obtaining (authorization code → token)
POST https://receiptroller.io/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code={authorization code}
&redirect_uri={registered URI}
&client_id={client ID}
&client_secret={client secret}
Response
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "rrrt_xxxxxxxxxxxx",
"scope": "store.read receipt.read"
}
Refreshing (refresh token → new access token)
POST https://receiptroller.io/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token={refresh token}
&client_id={client ID}
&client_secret={client secret}
The response contains a new access token and, in some cases, a new refresh token. If a new refresh token is returned, always save it and use it from then on (the old refresh token is invalidated).
Implementation patterns for refresh timing
- Proactive refresh: automatically refresh 5 minutes before expiry (recommended)
- Lazy refresh: refresh after receiving a 401 error and then retry
- Proactive + lazy combined: primarily proactive, with lazy also implemented in case of unexpected failures
In a system where many concurrent requests run, either consolidate the token refresh to a single worker or use a distributed lock to prevent double refreshes.
Cases where it is invalidated
- The refresh token's 90-day expiry passed
- The user disconnected the integration
- The secret was regenerated
- The app was suspended by an administrator
- There was no API access for a long time (30 days or more)
On invalidation, an invalid_grant error is returned. The app should guide the user to the re-authorization flow.
Storage
- Store tokens on the server side only. Avoid local storage of frontends / mobile apps
- When storing in a DB, encrypt (AES-256, etc.)
- Store per user; do not mix with other users' tokens
- Do not output to logs
Related guides
Published: 2026-04-27
Updated: 2026-07-05
Category
Tags
API (22)
OAuth (15)
Android (10)
iOS (9)
Webhook (6)
Troubleshooting (5)
api (5)
App registration (4)
POS Integration (4)
Reference (4)