For Partners¶
You are a partner if you are a company or large customer integrating many
Beyond users on a backend you control — white-label products, multi-tenant
platforms, or server-to-server automation. Partners authenticate with OAuth2
client credentials on a confidential client, can narrow access to a single
Beyond user or login with user_id / credential_id, and are typically
protected by an IP allowlist.
This is the path for trusted backend services that can store a client secret securely. This page is the end-to-end path: how authentication and token scoping work, then the onboarding flow from creating a user to activating a listing.
If instead you are an individual Beyond user automating your own listings, see For Personal Users.
When To Use This Path¶
Choose this profile if your integration:
- Runs on your servers, workers, or scheduled jobs.
- Needs machine-to-machine access without an end-user browser step.
- May optionally narrow access to one Beyond user at a time with
user_id. - May optionally narrow a user-scoped token further with
credential_id.
Recommended Configuration¶
| Setting | Value |
|---|---|
| App mode | partner |
| Client type | confidential |
| Primary grant | client_credentials |
| Access token lifetime | 1 hour |
For a comparison with personal automation flows and personal access tokens, read the Authentication overview first.
Get An Access Token¶
Confidential clients use the client credentials grant at /o/token/ and then
send the access token on /api/v1/* requests.
sequenceDiagram
participant Partner as PartnerBackend
participant Token as OAuthTokenEndpoint
participant API as PartnersAPI
Partner->>Token: POST /o/token/ grant_type=client_credentials
Note right of Partner: client_id, client_secret, scope optional user_id credential_id
Token-->>Partner: access_token, expires_in, token_type Bearer
Partner->>API: GET /api/v1/... Authorization Bearer access_token
API-->>Partner: JSON API response
curl -X POST $BASE_URL/o/token/ \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=listings:read user:read"
Response
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9...",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "listings:read user:read"
}
Building a client with AI
If you are scaffolding the client with an AI coding tool, give it both the schema-level and narrative context so it generates correct requests:
- OpenAPI specification —
/api/v1/schema/for precise endpoint contracts, field types, and request/response structures. - Full documentation (Markdown) —
/full-documentation.mdfor authentication, behavior details, and usage examples in one file.
Optional: Narrow A Token To One User¶
Partner apps can request a user-scoped token by adding user_id to the token
request. This is useful when your system manages multiple Beyond users and you
want a token that can only act on one of them.
curl -X POST $BASE_URL/o/token/ \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=listings:read user:read" \
-d "user_id=42"
The response includes user_id when the token is narrowed successfully.
Token Tiers And require_user_scoped_tokens¶
Beyond classifies scopes into tiers. These tiers decide whether a scope can be used on an application-level token, a user-scoped token, or both.
| Tier | Scopes | How to request | Behavior |
|---|---|---|---|
| App-level | user:write |
Omit user_id. |
Operates on the application as a whole. Rejected if you include user_id. |
| User-level | listings:read, listings:write, reservations:read, accounts:read, insights:read |
Include user_id when user-scoped tokens are required for your application. |
Acts only on the bound user's resources. If require_user_scoped_tokens is disabled, these scopes may also be used without user_id for application-level access. |
| Cross-tier | user:read |
Omit or include user_id. |
Without user_id, reads users owned by the application. With user_id, reads only the bound user. |
When require_user_scoped_tokens is enabled for your application, token
requests without user_id can still use app-level and cross-tier scopes
(user:write, user:read), but not user-level scopes. Requests with user_id
can use user-level and cross-tier scopes, but never user:write.
Optional: Narrow A User-Scoped Token To One Credential¶
If you want the token to behave exactly like one login credential within the
user, add credential_id. When omitted, Beyond uses the user's primary
credential by default.
curl -X POST $BASE_URL/o/token/ \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "scope=listings:read user:read" \
-d "user_id=42" \
-d "credential_id=314"
When credential_id is present, listing visibility and write access are
constrained by that credential's global permissions and grants.
Credential-scoped visibility rules¶
Once a token is bound to a credential, every endpoint that supports user-scoped tokens applies the rules below. The rules are identical for listings and managed accounts: managed accounts are narrowed only when at least one of their listings would also be narrowed.
credential_id present |
Credential global_permissions |
What the token can see and do |
|---|---|---|
| No (app-level token) | n/a | All resources owned by every user of the application. |
| Yes | ADMIN |
All listings and managed accounts owned by the bound user. GET /users/<id>/credentials/ returns every non-deleted credential. Can read resources and use listing write endpoints. |
| Yes | EDIT |
All listings and managed accounts owned by the bound user. GET /users/<id>/credentials/ returns only the acting credential. Can read resources and use listing write endpoints. |
| Yes | VIEW |
Same visibility as EDIT, but listing write endpoints return 403 Forbidden. |
| Yes | NONE |
Only listings explicitly granted to the credential; managed accounts are filtered to those that own at least one granted listing. GET /users/<id>/credentials/ returns only the acting credential. |
Soft-deleting a credential (for example, when a user removes a login) revokes
the credential for API purposes: any token bound to it will start returning
403 Forbidden immediately, and new token requests that resolve to a
soft-deleted credential are rejected at /o/token/.
Make Your First API Call¶
curl -X GET "$BASE_URL/api/v1/listings/?page[size]=5" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Accept: application/vnd.api+json"
End-to-End Onboarding Flow¶
Once your OAuth2 application has been provisioned, follow this flow to take a partner's user from creation to a listing that Beyond Pricing is actively pricing. It focuses on the order of operations and the background sync lifecycle, and links to the endpoint pages that document request details.
- Get an application-level token
- Create a user
- Add an account for that user
- Get a user-scoped token for that user
- Wait for the background sync to finish
- List the user's listings and map Beyond Pricing listing IDs to your listing IDs
- Enable the listing so the integration framework will begin pushing prices to the account
sequenceDiagram
participant Partner as PartnerSystem
participant BP as BeyondPricing
Partner->>BP: Get app-level token
Partner->>BP: Create user
BP-->>Partner: Return user_id
Partner->>BP: Add account for user
BP-->>Partner: Queue sync
Partner->>BP: Get user-scoped token for user
loop Until sync completes
Partner->>BP: List accounts for user
BP-->>Partner: sync-status = queued/in_progress/completed
end
Partner->>BP: List user's listings with user-scoped token
BP-->>Partner: listing id + channel-listings[].channel-id
Partner->>BP: Update listing activation
BP-->>Partner: Price syncing enabled
Step 1: Get an App-Level Token¶
Start with an application-level token so you can create the user and add the user's account. See Get An Access Token above for the client credentials request.
Note
In this onboarding flow, user and account creation use an app-level token
with user:write. After the account is created, request a user-scoped
token for that user so you can poll account status with user:read and
retrieve listings with listings:read.
Step 2: Create a User¶
Create the partner's user first. The user is the container for the account and for the listings that will later appear in Beyond Pricing.
Use the Create User endpoint details for the request and response schema.
Step 3: Add an Account for the User¶
After the user exists, add the partner's channel or PMS account for that user. This is the step that starts the import process for listings and reservation history.
Use the Add Account endpoint details for channel credentials, supported integrations, and response behavior.
Step 4: Get a User-Scoped Token¶
After the account exists, request a user-scoped token for that user. Use this token for user-specific reads in the remaining steps of the onboarding flow.
For collection endpoints such as
List Listings, a user-scoped token
automatically limits the response to the bound user, so you do not usually need
to add filter[owner]={user_id}.
Step 5: Wait for the Background Sync¶
After the account is created, Beyond Pricing starts a background sync that fetches reservation history for the listings associated with that account. This can take some time, especially for accounts with many listings or a large history.
Check the account's sync-status by polling /api/v1/users/{user_id}/accounts
with the List Accounts
endpoint until the state reaches completed.
Warning
Do not try to map listings or enable price syncing before the account sync has finished. Until sync is complete, the listing set may still be incomplete.
Step 6: Map Beyond Pricing Listing IDs to Your Listing IDs¶
Once the sync has completed, retrieve listings with the List Listings endpoint using the user-scoped token for that user. The response is already limited to that user's listings.
The Beyond Pricing listing ID is the top-level resource id. Your listing ID
from the connected channel or PMS is available in
channel-listings[].channel-id.
{
"id": "12345",
"channel-listings": [
{
"channel": "hostaway",
"channel-id": "external-listing-987"
}
]
}
See the Listings endpoint reference for filtering behavior, and the JSON:API guide for collection query conventions.
Step 7: Enable a Listing¶
Listings are created disabled on the Beyond Pricing side. After you have mapped the listing IDs, enable the listing so Beyond Pricing can start pushing prices to the connected account.
Use the Listing Activation endpoint reference for the activation payload and response shape.
Note
After a listing is activated, change its nightly base price through the Base Price customization endpoint. The base price is the anchor used by Beyond Pricing's algorithm, so keeping it accurate ensures recommended prices stay aligned with the partner's expectations.
After Activation¶
After a listing has been enabled, Beyond Pricing begins the normal price-syncing lifecycle for that listing.
If you need to inspect the listing again after activation, use the Get Listing Details endpoint. For API-wide error semantics, see Error Handling.
Security Notes¶
- Request only the scopes your integration needs.
- If Beyond has configured an IP allowlist for your application, the same IP
checks apply to both
/o/*and/api/v1/*. user:writeis app-level only and cannot be combined withuser_id.- When
require_user_scoped_tokensis enabled, request a user-scoped token withuser_idforlistings:read,listings:write,reservations:read,accounts:read, andinsights:read. user:readis cross-tier: application-level tokens read all users owned by the app; user-scoped tokens read only the bound user.- User-scoped tokens inherit the selected credential's permissions. A credential with limited listing grants will see and modify only the listings it is allowed to access.
Common Pitfalls¶
- Using the wrong token type. User and account creation require an app-level token, while listing retrieval is expected to use a user-scoped token for the target user. See Narrow A Token To One User.
- Starting listing mapping too early. Wait until account
sync-statusiscompleted. - Confusing Beyond Pricing listing IDs with external channel or PMS listing
IDs. Use the listing resource
idfor Beyond Pricing andchannel-listings[].channel-idfor your external identifier. - Forgetting that field names are dasherized in API payloads. See JSON:API Format.
Next Steps¶
- Review rate limiting before scheduling frequent jobs.
- Browse the endpoint reference.