Guide for native mobile apps: multi-business-account access and the OAuth flow
On ReceiptRoller, it is common for one user to belong to multiple business accounts. When you want to implement a "business account switcher" UI in a native mobile app (Android / iOS), using the pattern in this guide lets the user log in just once and access the data of all their business accounts.
How it works
Three mechanisms are combined.
- A user-scoped access token — the token is not bound to a specific business account (
AuthorizedOrganizationId = null, onlyAuthorizedUserIdis set) GET /api/v1/me/organizations— returns the list of business accounts the user belongs to- Attach
?organizationId=to each API — the server performs a membership check on every call
With this, the user performs the web-browser-based OAuth login just once and can then view and operate on all their business accounts while switching between them.
App registration settings
To use this pattern, turn off the "bind the token to one business account at authorization time" checkbox during app registration. You can set it on the app creation screen in the Developer Dashboard.
- Left on (the default) → a business account selection dialog is shown on the authorization screen, and the token is bound to the one account the user selects (for typical web apps / server integrations)
- Off → no account selection is shown on the authorization screen, and a user-scoped token is issued (this guide's target)
On the app list detail screen, apps with the flag off show a "multi-account support" badge.
OAuth authorization flow (PKCE + Chrome Custom Tabs / ASWebAuthenticationSession)
Follow the form recommended by RFC 8252 (OAuth 2.0 for Native Apps) and OAuth 2.1. Avoid an in-app WebView and use the system browser component.
- Android:
androidx.browser.customtabs.CustomTabsIntent - iOS:
AuthenticationServices.ASWebAuthenticationSession
Steps
- Register an OAuth client
- Create it manually from the Developer Dashboard: Creating a new app
- Turn off the "bind the token to one business account at authorization time" checkbox
- Set
redirect_urito a custom scheme (e.g.com.example.rrstore://oauth/callback) or an HTTPS App Links / Universal Links URL
- Generate PKCE parameters
code_verifier: a random string of 43-128 characterscode_challenge:BASE64URL(SHA256(code_verifier))state: a random value for CSRF protection
- Open
/oauth/authorizein the system browserhttps://receiptroller.io/oauth/authorize ?response_type=code &client_id={your_client_id} &redirect_uri={your_redirect_uri} &scope=sales.read sns.content.read sns.audience.read analytics.read store.customers.read store.flyers.read &state={state} &code_challenge={code_challenge} &code_challenge_method=S256If the user is not logged in, they are directed to
/Identity/Account/Login, and after logging in they return to the app'sredirect_urivia a consent screen (which shows only the requested scopes, with no business account selection).Note: if you have not turned off "bind the token to one business account at authorization time," an additional dropdown to choose "which business account to access" is shown here. To support multiple accounts, always turn it off.
- Exchange the authorization code for an access token
POST https://receiptroller.io/api/v1/auth/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code &code={code_from_redirect} &redirect_uri={your_redirect_uri} &client_id={your_client_id} &client_secret={your_client_secret} &code_verifier={code_verifier}The response is snake_case JSON per RFC 6749 §5.1.
{ "access_token": "...", "refresh_token": "...", "token_type": "Bearer", "expires_in": 3600, "scope": "sales.read sns.content.read sns.audience.read analytics.read store.customers.read store.flyers.read" }
Get the business accounts the user belongs to
Use the access token to retrieve the list of business accounts.
GET https://receiptroller.io/api/v1/me/organizations
Authorization: Bearer {access_token}
Response:
{
"organizations": [
{ "id": "9f0dfdc3-77ac-4bf7-9c9e-a5d1285edd88", "name": "AB", "role": "SuperUser,StoreStaff" },
{ "id": "55a5b9bf-287c-4618-a973-66b67004f292", "name": "モスフードサービス", "role": "Admin" }
]
}
Show this response as a "business account switcher" UI in the app. Hold the id of the business account the user selects locally and use it in subsequent API calls.
Pass ?organizationId= to each API
Attach the selected business account ID as a query parameter on every call. The server verifies "whether the calling user is a member of that business account" on every call (to prevent cross-org data leaks).
GET https://receiptroller.io/api/v1/sales/kpis?organizationId={selected_org_id}&storeId={store_id}
Authorization: Bearer {access_token}
List of APIs that support multi-business-account access
As of May 2026, the following endpoint groups support the user-scoped token and the ?organizationId= pattern.
Common
GET /api/v1/me/organizations— the list of business accounts the user belongs to
Sales / analytics
GET /api/v1/sales/kpisGET /api/v1/sales/trendGET /api/v1/sales/adviceGET /api/v1/sales/forecastGET /api/v1/sales/products— products + ABC analysisGET /api/v1/sales/visitors— visitor analysisGET /api/v1/sales/churn— churn risk scoreGET /api/v1/sales/recommendations— product recommendationsGET /api/v1/sales/multi-trend— multi-store comparison
SNS
GET /api/v1/sns/accounts//accounts/{id}GET /api/v1/sns/posts//posts/{id}//posts/{id}/analyticsGET /api/v1/sns/comments
Customers (CRM)
GET /api/v1/store/customers//customers/{id}POST /api/v1/store/customers(upsert)DELETE /api/v1/store/customers/{id}GET /api/v1/store/customers/{id}/purchases
Flyers
GET /api/v1/organizations/{orgId}/stores/{storeId}/flyersGET /api/v1/organizations/{orgId}/stores/{storeId}/flyers/{flyerId}POST/PUT/DELETE/ publish / unpublish / expire
The flyer endpoints include {orgId} in the URL path, so attaching ?organizationId= is not needed. The server verifies "whether the user can access the orgId in the URL path" on every call.
Sample: get sales KPIs on Android
// 1. After login → get the business account list with /api/v1/me/organizations
val orgs = api.getMyOrganizations() // Authorization: Bearer ... is attached
showOrgSwitcher(orgs)
// 2. The user selects a business account
val selectedOrgId = "55a5b9bf-287c-4618-a973-66b67004f292"
// 3. Get the sales KPIs
val kpis = api.getSalesKpis(organizationId = selectedOrgId, storeId = "abc123")
showDashboard(kpis)
// 4. No token re-fetch needed when switching business accounts — just change selectedOrgId and request again
val newOrgId = "9f0dfdc3-77ac-4bf7-9c9e-a5d1285edd88"
val newKpis = api.getSalesKpis(organizationId = newOrgId, storeId = "xyz789")
Security considerations
- Handling client_secret — for a public client (a mobile app alone), the recommended configuration is
token_endpoint_auth_method=none, which authenticates with PKCE only and does not include the client_secret in the app binary. - Where to store tokens — use the OS's secure area, such as the Android Keystore / iOS Keychain.
- Lifetimes — access_token is 1 hour, refresh_token is 30 days. The refresh_token is issued as single-use (rotation scheme).
- Scope minimization — request only the scopes you need. OAuth scope list
- Server-side membership check — if you specify an
organizationIdfor a business account the user does not belong to, the API returns 403 Forbidden.
Related articles
-
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.
-
Setting the redirect URLExplains the role of the redirect URI (callback URL) you set in the ReceiptRoller developer portal, the registration rules, using development vs. production environments, and common errors and how to handle them.
-
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.