Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Beyond Accounts API
version: 2.0.0
description: Bearer-protected API for third-party integrations. Supports OAuth2 client credentials and personal access tokens. Follows JSON:API specification.
tags:
- name: Accounts
paths:
/api/v1/users/{user_id}/accounts/:
get:
operationId: list_accounts
description: 'Return a paginated list of accounts (channel connections) for the specified user.
## Response Codes
- **200**: Success
- **401**: Unauthorized - invalid or missing OAuth2 token
- **403**: Forbidden - insufficient scope
- **404**: Not found - user not found'
summary: List accounts for a user
parameters:
- in: path
name: user_id
schema:
type: integer
required: true
- name: page[number]
required: false
in: query
description: A page number within the paginated result set.
schema:
type: integer
- name: page[size]
required: false
in: query
description: Number of results to return per page.
schema:
type: integer
tags:
- Accounts
security:
- oauth2:
- user:read
- personalAccessToken: []
responses:
'200':
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/PaginatedAccountList'
examples:
AccountList:
value:
data:
- data:
- type: accounts
id: '123'
attributes:
user-id: 456
channel: hostaway
channel-id: hw-account-789
channel-display-id: null
label: Hostaway
email: user@example.com
valid: true
nb-enabled-listings: 12
nb-listings: 15
is-pms: true
sync-status:
state: completed
last-successful-sync-at: '2026-08-09T04:12:44Z'
meta:
pagination:
page: 1
pages: 1
count: 1
links:
first: http://example.com/articles?page%5Bsize%5D=10&page%5Bnumber%5D=1
last: http://example.com/articles?page%5Bsize%5D=10&page%5Bnumber%5D=9
prev: http://example.com/articles?page%5Bsize%5D=10&page%5Bnumber%5D=1
next: http://example.com/articles?page%5Bsize%5D=10&page%5Bnumber%5D=3
meta:
pagination:
count: 42
page: 2
pages: 5
summary: Account list
description: ''
'401':
description: Unauthorized - invalid or missing bearer token
'403':
description: Forbidden
'404':
description: Not found - resource does not exist
'429':
description: Rate limit exceeded
'500':
description: Internal server error
post:
operationId: create_account
description: 'Add a channel connection (account) for a user. Each channel requires specific credentials. Creating an account starts a background import. Use the optional `sync-priority` query parameter to say how soon that import starts: `high` (the default) starts it as soon as Beyond can, `normal` can take longer to start when Beyond is busy. Send `normal` when you add many accounts at once and none of them is urgent.'
summary: Add an account for a user
parameters:
- in: path
name: user_id
schema:
type: integer
required: true
- in: query
name: sync-priority
schema:
type: string
enum:
- high
- normal
default: high
description: How soon the account's import starts. `high` (the default) starts it as soon as Beyond can. `normal` can take longer to start when Beyond is busy, which suits adding many accounts at once. Any other value is a `400`.
tags:
- Accounts
requestBody:
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/AccountCreateRequest'
examples:
APIKeyChannel(Hostify):
value:
data:
type: accounts
attributes:
channel: hostify
credentials:
api_key: your-api-key-here
summary: Add an API key channel
ClientID/SecretChannel(Hostaway):
value:
data:
type: accounts
attributes:
channel: hostaway
credentials:
client_id: '12345'
client_secret: abcdef123456
summary: Add a client ID/secret channel
JWTChannel(Guesty):
value:
data:
type: accounts
attributes:
channel: guesty
credentials:
jwt: your-jwt-token-here
summary: Add a JWT-based channel
required: true
security:
- oauth2:
- user:write
- personalAccessToken: []
responses:
'201':
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/AccountResponse'
examples:
SuccessfulResponse(201):
value:
data:
type: accounts
id: '123'
attributes:
user-id: 456
channel: hostaway
channel-id: hw-account-789
channel-display-id: null
label: Hostaway
email: user@example.com
valid: true
nb-enabled-listings: 0
nb-listings: 0
is-pms: true
sync-status:
state: queued
last-successful-sync-at: null
summary: Successful response (201)
description: ''
'400':
description: Validation error
'401':
description: Unauthorized - invalid or missing bearer token
'403':
description: Forbidden
'404':
description: Not found - resource does not exist
'409':
description: Conflict - the request timed out waiting for a concurrent operation on the same account; nothing was applied, so it is safe to retry
'422':
description: Unprocessable entity
'429':
description: Rate limit exceeded
'500':
description: Internal server error
'502':
description: Channel error
/api/v1/users/{user_id}/accounts/{account_id}/:
get:
operationId: get_account
description: 'Retrieve a single account (channel connection) for the specified user.
## Response Codes
- **200**: Success
- **401**: Unauthorized - invalid or missing OAuth2 token
- **403**: Forbidden - insufficient scope
- **404**: Not found - user or account not found'
summary: Get an account for a user
parameters:
- in: path
name: user_id
schema:
type: integer
required: true
- in: path
name: account_id
schema:
type: integer
required: true
tags:
- Accounts
security:
- oauth2:
- user:read
- personalAccessToken: []
responses:
'200':
content:
application/vnd.api+json:
schema:
$ref: '#/components/schemas/AccountResponse'
description: ''
'401':
description: Unauthorized - invalid or missing bearer token
'403':
description: Forbidden
'404':
description: Not found - resource does not exist
'429':
description: Rate limit exceeded
'500':
description: Internal server error
delete:
operationId: delete_account
description: 'Remove a channel connection (account) for a user. This unregisters webhooks and soft-deletes the account.
## Response Codes
- **204**: Successfully deleted
- **401**: Unauthorized - invalid or missing OAuth2 token
- **403**: Forbidden - insufficient scope
- **404**: Not found - user or account not found, including an account a concurrent request already deleted
- **409**: Conflict - the request timed out waiting for a concurrent operation on the same account; retry shortly'
summary: Delete an account for a user
parameters:
- in: path
name: user_id
schema:
type: integer
required: true
- in: path
name: account_id
schema:
type: integer
required: true
tags:
- Accounts
security:
- oauth2:
- user:write
- personalAccessToken: []
responses:
'204':
description: No content
'401':
description: Unauthorized - invalid or missing bearer token
'403':
description: Forbidden
'404':
description: Not found - resource does not exist
'409':
description: Conflict - the request timed out waiting for a concurrent operation on the same account; nothing was applied, so it is safe to retry
'429':
description: Rate limit exceeded
'500':
description: Internal server error
/api/v1/users/{user_id}/accounts/{account_id}/refresh/:
post:
operationId: refresh_account
description: 'Queue a full listings and reservations refresh for the specified account.
This endpoint enqueues an asynchronous `sync_all` job and returns immediately.
Use `recent-sync-threshold-minutes` to control how recently synced listings are skipped. The threshold unit is minutes. When set to `0`, the refresh includes all listings. The snake_case spelling `recent_sync_threshold_minutes` is deprecated but still accepted.
Use the optional `sync-priority` query parameter to say how soon the refresh starts: `high` (the default) starts it as soon as Beyond can, `normal` can take longer to start when Beyond is busy. Send `normal` when you refresh many accounts at once and none of them is urgent.
If you have registered a webhook, an `account.refreshed` event is delivered once the listing sync reaches a terminal state, so you do not have to poll. Reservations are refreshed by separate background jobs and are still in flight when that event fires.
## Response Codes
- **400**: Validation error - invalid query parameter value
- **202**: Refresh accepted and queued
- **401**: Unauthorized - invalid or missing OAuth2 token
- **403**: Forbidden - insufficient scope
- **404**: Not found - user or account not found
- **409**: Conflict - a refresh is already in progress; retry shortly'
summary: Refresh an account for a user
parameters:
- in: path
name: user_id
schema:
type: integer
required: true
- in: path
name: account_id
schema:
type: integer
required: true
- in: query
name: recent-sync-threshold-minutes
schema:
type: integer
default: 60
description: Skip listings synced within the last N minutes. Defaults to 60. Set to 0 to disable this optimization and refresh all listings.
- in: query
name: recent_sync_threshold_minutes
schema:
type: integer
description: Deprecated spelling of `recent-sync-threshold-minutes`, kept for existing integrations. Ignored when both are sent.
deprecated: true
- in: query
name: sync-priority
schema:
type: string
enum:
- high
- normal
default: high
description: How soon the refresh starts. `high` (the default) starts it as soon as Beyond can. `normal` can take longer to start when Beyond is busy, which suits refreshing many accounts at once. Any other value is a `400`.
tags:
- Accounts
security:
- oauth2:
- user:write
- personalAccessToken: []
responses:
'400':
description: Validation error
'202':
description: Refresh accepted
'401':
description: Unauthorized - invalid or missing bearer token
'403':
description: Forbidden
'404':
description: Not found - resource does not exist
'409':
description: Conflict - a refresh is already in progress for this account
'429':
description: Rate limit exceeded
'500':
description: Internal server error
components:
schemas:
AccountSyncStatus:
type: object
description: 'Serializer for the account sync status.
Receives the full ManagedAccount instance via ``source="*"`` and derives
the sync state from the pending sync job and ``listings_synced_at``.'
properties:
state:
allOf:
- $ref: '#/components/schemas/StateEnum'
description: 'Current sync state: queued, in_progress, completed, or unknown
* `queued` - queued
* `in_progress` - in_progress
* `completed` - completed
* `unknown` - unknown'
last-successful-sync-at:
type:
- string
- 'null'
format: date-time
description: Timestamp of the last successful listing sync, or null if never synced
required:
- last-successful-sync-at
- state
Account:
type: object
required:
- type
- id
additionalProperties: false
properties:
type:
allOf:
- $ref: '#/components/schemas/AccountResourceTypeEnum'
description: The [type](https://jsonapi.org/format/#document-resource-object-identification) member is used to describe resource objects that share common attributes and relationships.
id:
type: string
description: Unique identifier for the account
attributes:
type: object
properties:
user-id:
type: integer
description: ID of the user who owns this account
channel:
type: string
description: Channel identifier (e.g., 'airbnb', 'guesty')
channel-id:
type: string
description: Account identifier on the channel side
channel-display-id:
type:
- string
- 'null'
description: Human-readable display ID
label:
type: string
description: Human-readable channel label
email:
type:
- string
- 'null'
description: Email associated with this account
valid:
type: boolean
description: Whether the account credentials are currently valid
nb-enabled-listings:
type: integer
readOnly: true
description: Number of enabled listings in this account
nb-listings:
type: integer
readOnly: true
description: Total number of listings in this account
is-pms:
type: boolean
readOnly: true
description: Whether this channel is a property management system
sync-status:
allOf:
- $ref: '#/components/schemas/AccountSyncStatus'
readOnly: true
description: Status of the account sync process started after account connection
required:
- user-id
- channel
- channel-id
- channel-display-id
- label
- email
- valid
AccountResourceTypeEnum:
type: string
enum:
- accounts
AccountCreateRequest:
type: object
properties:
data:
type: object
required:
- type
additionalProperties: false
properties:
type:
type: string
description: The [type](https://jsonapi.org/format/#document-resource-object-identification) member is used to describe resource objects that share common attributes and relationships.
enum:
- accounts
attributes:
type: object
properties:
channel:
type: string
minLength: 1
description: 'Channel identifier (e.g., ''hostify'', ''hostaway''). Supported channels: airbnb, airbnb_partner, avantio, barefoot_direct, beds24, best_beach, booking_connect, booking_experts, bookingsync, brightside, ciirus, cloudbeds, direct, elina, escapia, fake, fake_2, fake_pms, fantasticstay, gfh, guesty, homeaway, homhero, homhero_staging, hospitable, hostaway, hostfully, hosthub, hostify, icnea, igms, ipro, janiis, kigo, kigo_pro, kross_booking, lightmaker, liverez, lodgable, lodgify, lodgify_partner, lodgix, loggia, mews, myvr, octorate, opera, ownerrez, real_time_rental, rentalready, rentals_united, resly, rms, secra, septeo, smoobu, stays, streamline, supercontrol, tokeet, track, travelmob, uplisting, villas365, vrbo, vreasy, vrm, zeevou, zeevou_direct'
credentials:
type: object
additionalProperties: {}
description: Credentials for the specified channel
required:
- channel
- credentials
required:
- data
PaginatedAccountList:
type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Account'
links:
type: object
description: Pagination links for the primary data. These keys MUST be used for pagination links; each MUST be omitted or `null` when that link is unavailable. Values follow JSON:API link rules (URI string, link object, or null). https://jsonapi.org/format/#fetching-pagination https://jsonapi.org/format/#document-links
properties:
first:
type:
- string
- 'null'
format: uri
example: http://example.com/articles?page%5Bsize%5D=10&page%5Bnumber%5D=1
description: 'The first page of data. A JSON:API link: URI string, link object, or null. See https://jsonapi.org/format/#document-links.'
last:
type:
- string
- 'null'
format: uri
example: http://example.com/articles?page%5Bsize%5D=10&page%5Bnumber%5D=9
description: 'The last page of data. A JSON:API link: URI string, link object, or null. See https://jsonapi.org/format/#document-links.'
prev:
type:
- string
- 'null'
format: uri
example: http://example.com/articles?page%5Bsize%5D=10&page%5Bnumber%5D=1
description: 'The previous page of data. A JSON:API link: URI string, link object, or null. See https://jsonapi.org/format/#document-links.'
next:
type:
- string
- 'null'
format: uri
example: http://example.com/articles?page%5Bsize%5D=10&page%5Bnumber%5D=3
description: 'The next page of data. A JSON:API link: URI string, link object, or null. See https://jsonapi.org/format/#document-links.'
additionalProperties: false
meta:
type: object
description: Non-standard meta-information. Page-number stacks often nest totals under `pagination`. JSON:API does not define these keys. Servers MAY add other `meta` members; this schema documents the usual djangorestframework-json-api shape only. https://jsonapi.org/format/#document-meta
properties:
pagination:
type: object
description: Typical page-number metadata from djangorestframework-json-api; not mandated by JSON:API.
properties:
count:
type: integer
minimum: 0
example: 42
description: Total number of resources across all pages.
page:
type: integer
minimum: 1
example: 2
description: Current page number (1-based).
pages:
type: integer
minimum: 0
example: 5
description: Total number of pages.
additionalProperties: false
additionalProperties: false
required:
- data
AccountResponse:
type: object
properties:
data:
$ref: '#/components/schemas/Account'
required:
- data
StateEnum:
enum:
- queued
- in_progress
- completed
- unknown
type: string
description: '* `queued` - queued
* `in_progress` - in_progress
* `completed` - completed
* `unknown` - unknown'
securitySchemes:
oauth2:
type: oauth2
description: Use OAuth2 client credentials to mint an application token, or add `user_id` and optional `credential_id` in the Authorize dialog to request a user- or credential-scoped token.
flows:
clientCredentials:
tokenUrl: /o/token/
refreshUrl: /o/token/
scopes:
listings:read: Read listings
listings:write: Modify listings
reservations:read: Read reservations
accounts:read: Read account information
user:read: Read user information
user:write: Create and modify users
insights:read: Read market insights
compsets:read: Read competitive set data
neyoba:ask: Ask Neyoba
beyond:read: Read listings, performance, and market data via the Beyond MCP server
beyond:write: Modify pricing and listing settings via the Beyond MCP server
beyond:skills: Load Beyond revenue-management skills via the Beyond MCP server
beyond:usage: Read tool-call history and usage via the Beyond MCP server
webhooks:read: Read delivered webhook events
webhooks:write: Modify webhook configuration
personalAccessToken:
type: http
scheme: bearer
bearerFormat: PersonalAccessToken
description: Paste a `bpat_...` personal access token. PATs use the same Bearer header as OAuth2 tokens and must still include the runtime-required scopes for each endpoint, even though OpenAPI cannot encode scopes for non-OAuth bearer schemes.
x-provenance:
method: harvested
publisher: Beyond Pricing
source: https://developers.beyondpricing.com/api/v1/schema/
note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
stamped by stamp-openapi-provenance.py (roadmap#793)