Accounts¶
Accounts represent channel connections (e.g., Airbnb, Hostaway, or other PMS accounts) linked to a user.
| Endpoint | Method | Scope | Description |
|---|---|---|---|
/api/v1/users/<user_id>/accounts/ |
GET | user:read |
List accounts for a user |
/api/v1/users/<user_id>/accounts/ |
POST | user:write |
Add an account for a user |
/api/v1/users/<user_id>/accounts/<account_id>/ |
GET | user:read |
Get one account for a user |
/api/v1/users/<user_id>/accounts/<account_id>/refresh/ |
POST | user:write |
Queue a full refresh for an account |
/api/v1/users/<user_id>/accounts/<account_id>/ |
DELETE | user:write |
Delete an account |
Try it out
Explore parameters, schemas, supported channels with their required credentials, and live requests in the Swagger UI.
List Accounts¶
Returns a paginated list of accounts (channel connections) for the specified user.
Use this endpoint to monitor the background import that starts after an account is created. The response includes sync-status, which can be used to detect whether the account is still queued, in_progress, or completed.
For the end-to-end workflow, see the partner onboarding flow.
Request¶
| Parameter | Description |
|---|---|
page[number], page[size] |
Standard pagination. Default page size 25, maximum 100. Newest accounts first. |
Response¶
{
"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}
}
}
| Field | Description |
|---|---|
user-id |
The user who owns this account. |
channel |
Channel identifier (e.g. airbnb, hostaway, guesty). |
channel-id |
The account's identifier on the channel side. |
channel-display-id |
Human-readable channel-side id, when the channel provides one; null otherwise. |
label |
Human-readable channel label. |
email |
Email associated with this account on the channel; null when the channel does not expose one. |
valid |
Whether the stored credentials are currently valid on the channel. |
nb-listings, nb-enabled-listings |
Total and enabled listing counts imported from this account. |
is-pms |
Whether this channel is a property management system. |
sync-status.state |
queued, in_progress, completed, or unknown. |
sync-status.last-successful-sync-at |
Timestamp of the last successful listing sync; null if never synced. |
Get Account¶
GET /api/v1/users/<user_id>/accounts/<account_id>/ returns one account, with
the same attributes as the list entries above. 404 when the user or account
is not visible to your token.
Add Account¶
Add a channel connection (account) for a user. Each channel requires specific credentials (API key, client ID/secret, JWT, etc.). The Swagger UI documents the complete list of 50+ supported channels and the credentials each one requires.
User-scoped tokens may call this endpoint, but the bound credential must have global edit or admin permissions.
Request¶
{
"data": {
"type": "accounts",
"attributes": {
"channel": "hostaway",
"credentials": {
"client_id": "12345",
"client_secret": "abcdef123456"
}
}
}
}
| Field | Description |
|---|---|
channel |
Required. Channel identifier (e.g. hostify, hostaway, guesty). An unsupported value is a 400. |
credentials |
Required. Channel-specific credential object — the field set differs per channel and is validated against that channel's schema. See the Swagger UI for every channel's required fields. Credential keys are snake_case, as shown. |
The endpoint also accepts one optional query parameter:
| Parameter | Description |
|---|---|
sync-priority |
Optional. high (the default) or normal. See Sync priority below. Any other value is a 400. |
Returns 201 Created with the account resource (same shape as the list
entries), with sync-status.state still queued.
If channel validation or authentication fails, the API returns 422 Unprocessable Entity with a meta.channel field identifying which channel failed and a meta.code field with the error type.
Send one request per account and wait for it to answer before sending another. Several POST /accounts/ calls for the same user and channel in flight at once all resolve to the same account and are applied one at a time; a request that waits too long for its turn — because another create or a credentials refresh for the same account is still running — is rejected with 409 Conflict and code: "concurrent_modification". It changed nothing and is safe to retry, but the wait is avoidable by not sending requests concurrently. See 409 -- Conflict.
Creating an account starts a background sync that imports reservation history and creates listings for the connected account. Rather than polling sync-status, subscribe to the account.created webhook, which fires once that sync finishes and reports how many listings were created.
Sync priority¶
The sync-priority query parameter tells Beyond how soon the account's import should start.
| Value | Effect | Use it when |
|---|---|---|
high |
Beyond starts the import as soon as it can. | Someone is waiting on the result, for example an account connected during an interactive signup. |
normal |
The import can take longer to start when Beyond is busy. | You add many accounts at once and none of them is urgent. |
The parameter is optional. A request that leaves it out is treated as high.
Priority affects only how soon the import starts. Either value imports the same data and fires the same account.created webhook.
The request body is unchanged:
{
"data": {
"type": "accounts",
"attributes": {
"channel": "hostify",
"credentials": {
"api_key": "your-api-key-here"
}
}
}
}
Refresh Account¶
Queue a full listings and reservations refresh for an existing account.
User-scoped tokens may call this endpoint, but the bound credential must have global edit or admin permissions.
Use this endpoint when you want to manually trigger another import after the account has already been connected, for example after fixing channel-side data issues or when you want to force a fresh sync without reconnecting the account.
This refresh is prioritized ahead of normal queued work and replaces an existing pending account refresh that has not started yet.
If a sync for the account is already running, the API returns 409 Conflict instead of queuing another one. Wait for the in-progress sync to finish (or for the account.refreshed webhook, if registered) and retry shortly.
Request¶
| Parameter | Description |
|---|---|
recent-sync-threshold-minutes |
Optional. Skip listings synced within the last N minutes. Defaults to 60; 0 disables the skip and refreshes all listings. A non-integer value is a 400. |
The snake_case spelling recent_sync_threshold_minutes is deprecated. The endpoint still accepts it, so existing integrations keep working, but new integrations must use recent-sync-threshold-minutes. When a request carries both, the dasherized name wins.
No request body. The endpoint returns 202 Accepted once the refresh job is
queued:
{
"meta": {
"status": "accepted",
"message": "Refresh queued",
"recent-sync-threshold-minutes": 60
},
"links": {
"related": "$BASE_URL/api/v1/users/456/accounts/123/"
}
}
The refresh runs asynchronously — poll the account's sync-status via
links.related, or subscribe to the
account.refreshed webhook. Reservations
are refreshed by separate background jobs and can still be in flight when that
event fires.
Delete Account¶
Remove an account (channel connection) for the specified user.
User-scoped tokens may call this endpoint, but the bound credential must have global edit or admin permissions.
Returns 204 No Content on success.
Deleting and Re-creating an Account¶
Deleting an account is a soft delete: the account and its listings are retained, not erased. Re-creating the account with the same channel and credentials revives the same account, and its previously synced listings are resurrected on the next sync rather than being recreated from scratch.
Two conditions must hold for recovery to work:
- The credentials must still be valid on the channel. A revoked or invalid key returns
422with aInvalid Credentialserror instead of reviving the account. - The channel must return the same account and listing IDs as before.
Errors¶
| Status | Cause |
|---|---|
400 |
Unsupported channel, credentials failing the channel's schema, or an invalid recent-sync-threshold-minutes. |
401 |
Missing or invalid bearer token. |
403 |
Token lacks the required scope, or the bound credential lacks global edit/admin permissions for a write. |
404 |
User or account not found, or not visible to your token. |
409 |
Refresh requested while a sync is already running for the account (code: "sync_in_progress"), or the request timed out waiting for a concurrent operation on the same account (code: "concurrent_modification"). Both are transient — nothing about the request needs to change before retrying. |
422 |
Channel validation/authentication failed (meta.channel names the channel, meta.code the error type). |
429 |
Rate limit exceeded — refresh is additionally capped at 100 requests/minute. See Rate Limiting. |
502 |
The channel's own API failed while validating the connection. Transient — retry with backoff. |