Setting the redirect URL
For developers registering an app in the ReceiptRoller developer portal. It explains how to set the redirect URI (callback URL) used in the OAuth 2.0 authorization code flow, and the cautions involved.
The redirect URI is the URL that receives the authorization code after the user presses "Allow" on the authorization screen in the OAuth flow. The URI you register at app registration and the redirect_uri you specify when actually sending a request to /oauth/authorize must match exactly.
The role of the redirect URI
In the OAuth authorization code flow, the values are passed in the following order.
- The app sends the user to ReceiptRoller's authorization screen (including
redirect_uri) - The user presses "Allow"
- ReceiptRoller redirects to the registered redirect URI with a
codeparameter - The app obtains an access token using the
code
If you specify a redirect URI that is not registered, or one that differs by even a single character from the registered value, ReceiptRoller does not return an authorization code and instead returns an invalid_redirect_uri error. This is a mechanism to prevent an attacker from stealing the code.
Registration rules
| Item | Rule |
|---|---|
| Scheme | https:// required (production)http://localhost and http://127.0.0.1 allowed only in development |
| Host | A fully qualified domain name. Wildcards (*.example.com) not allowed |
| Path | Arbitrary. A conventional path such as /oauth/callback or /auth/rr/callback is recommended |
| Query / fragment | Do not include them in the registered URI. Pass dynamic parameters via state |
| Number registrable | Up to 10 per app |
| Case sensitivity | Distinguished. /Callback and /callback are different |
| Trailing slash | Distinguished. /callback and /callback/ are different |
Using development vs. production environments
Many apps have multiple environments: "development", "staging", "production". On ReceiptRoller you can register multiple redirect URIs per app, so adding a URI per environment is the basic approach.
Recommended pattern
https://app.example.com/oauth/callback ← production https://staging.example.com/oauth/callback ← staging http://localhost:3000/oauth/callback ← development (local)
You can also separate apps by environment, but we strongly recommend always separating the production app from the development app. The reasons are as follows.
- You no longer need to distribute the production client secret to every developer
- You prevent accidents where a development-time glitch mistakenly invalidates production users' tokens
- User-scope review completes for the production app alone
http://localhost for a production app. If a secret leaks, an attacker could lure authorization codes to a fake local site.
Registration procedure
- Developer portal → app list → open the target app
- Click the "+ Add" button in the "Redirect URI" section
- Enter the URI and "Save"
- Repeat for as many environments as needed
Registered URIs take effect immediately. No rebuild or redeploy of the app is needed.
Leveraging the state parameter
Pass dynamic information (the URL of the page you came from, the user ID, a CSRF token, etc.) via the state parameter rather than embedding it directly in the redirect URI. ReceiptRoller returns state as-is after authorization, so you can restore it on the callback side.
// Authorization request https://receiptroller.io/oauth/authorize ?client_id=xxx &redirect_uri=https://app.example.com/oauth/callback &state=eyJjc3JmIjoiYWJjMTIzIiwicmV0dXJuIjoiL2Rhc2hib2FyZCJ9 &scope=store.read &response_type=code // Callback https://app.example.com/oauth/callback ?code=... &state=eyJjc3JmIjoiYWJjMTIzIiwicmV0dXJuIjoiL2Rhc2hib2FyZCJ9
state is also required as a CSRF countermeasure. Save a random value generated at request time in the session, and verify it matches on callback.
Common errors
| Error | Cause | What to do |
|---|---|---|
invalid_redirect_uri |
Does not match the registered URI | Check that it matches exactly, including case, trailing slash, and port |
redirect_uri_required |
The authorization request does not include redirect_uri |
Always add it to the query parameters |
insecure_redirect_uri |
Tried to register http:// (other than localhost) on a production app |
Change it to https:// |
| No callback after authorization | DNS/certificate error on the registered URI's host | Open that URI directly in a browser to confirm reachability |
Cautions when changing it
When changing the redirect URI of a live app, follow this order.
- Add the new URI (keep the old URI)
- Switch the app's code / environment variables to the new URI and deploy
- Verify behavior with the new URI
- Delete the old URI
If you delete the old URI abruptly, all authorization requests that occur before the deploy completes will fail.
Related guides
-
Using the Store Information APIA guide to the REST API for fetching and updating a store's basic information (store name, store type, contact details, and address). Lets you implement a store information editing screen from token-authenticated clients such as staff apps.
-
Using the Business Hours APIA guide to ReceiptRoller's Business Hours API (/api/v1/stores/{storeId}/business-hours). Covers retrieving and updating per-day business hours, registering special business days (temporary closures and hour changes), configuring a store's workable hours (the upper bound for shift creation), and determining whether the store is currently open.
-
Using the Orders / OMS APIA guide to CRUD operations on the orders under a business account using ReceiptRoller's Orders / OMS API (/api/v1/orders). Covers creating, updating, transitioning status (confirm, process, cancel), and deleting orders, plus the flow for Android / iOS apps and server integrations.
-
Using the Products APIA guide to CRUD operations on products under a business account using the ReceiptRoller Products API (/api/v1/products). An introductory article for reading and writing the PIM (product master) from an Android/iOS app or server integration.
-
Using the Sales APIAn overview of ReceiptRoller's Sales API (/api/v1/sales/*) and how to filter by business account, store, POS terminal, and period. A getting-started guide covering the actual response structure (the KpiValue nested type) through averageTicket and the 8-hour token lifetime, for building a sales dashboard in an Android/iOS mobile app or server integration.