Guesty Open API: Quick start and troubleshooting

This guide is for developers integrating with Guesty's Open API for the first time. Full reference: open-api-docs.guesty.com 

 

Quick start

1. Get your credentials

Start by making sure your Guesty account has Open API access. You will need to get your OAuth credentials: client_id and client_secret. For step-by-step instructions, see Get Started.

 

2. Authenticate

Exchange your credentials for a bearer token: POST https://open-api.guesty.com/oauth2/token with grant_type=client_credentials, scope=open-api, client_id, and client_secret. The token is valid for 24 hours.

Keep your token secure and monitor its expiration time. Each client_id can request a new token up to five times in 24 hours. If you reach this limit, you will not be able to get a new token until the window resets. To prevent problems, plan to refresh your token a few minutes before it expires. For sample code in Node.js, Python, and PHP, see the Access Token Management recipe. For more details, see Authentication.

 

3. Make your first call

Send the token as a bearer header on every request:

GET https://open-api.guesty.com/v1/listings
Authorization: Bearer {access_token}

 

4. Handle pagination

Most endpoints use limit and skip query parameters for pagination and return items, count, limit, and skip in the response. Some endpoints may use offset or cursor, or return a different response format. If the standard parameters do not work, review the reference page for that specific endpoint. For example:

  • offset instead of skip: GET /properties-api/groups/group
  • cursor-based: GET /communication/conversations, GET /communication/conversations/{conversationId}/posts
  • results + a nested pagination object: GET /reservations-v3/search (the same v3 Search Reservations endpoint used elsewhere in this guide)
  • results/count instead of items/count: GET /vendors, GET /users, GET /property-logs/{id}

 

Troubleshooting & FAQ

Before retrying a request, check the status code. Only 429 and 5xx errors should be retried automatically. Other status codes indicate that the request needs to be modified before retrying.

 

By response code

401 / 403 — "Unauthorized" right after I authenticated: Your token expired (they last 24 hours) or wasn't sent correctly. Note: Guesty's API returns a 403 even when the message says "Unauthorized"—that's expected, not a bug on your end. Fix: re-authenticate and re-cache the token; confirm the header is exactly Authorization: Bearer <token>. The token endpoint also exposes x-ratelimit-remaining-day / x-ratelimit-limit-day headers if you want to watch your daily token budget directly. More: Authentication.

404 — resource not found, but the ID looks right: Usually, the ID belongs to a different account/scope than your token, or the record hasn't synced yet, or comes from a channel with limited API visibility. Confirm the ID against the dashboard for the same account your credentials belong to. For example, GET /reservations-v3/group/{groupId} returns 404 for a valid-looking ID under the wrong account just as readily as a nonexistent one. More: Response Codes.

410 — quote expired: Quotes have a fixed expiration window. Once expired, that quote can't be modified or booked — create a new one rather than retrying the old ID.

400 / 422 — validation error: Check the request body against that endpoint's schema on its reference page. Guesty's error responses aren't one consistent shape across the whole API — some nest fields under error, some don't, and field names vary — so don't assume an error field name from one endpoint applies to another. For example, POST /reservations-v3 (quick booking) returns both 400 and 422 depending on whether the request itself is malformed or violates a booking rule (e.g., unavailable dates) — check which one you got before assuming the fix.

429 — rate limited: This means you have reached the account-wide limit of 15 requests per second, 120 per minute, or 5,000 per hour, shared across all tokens. Wait for the time specified in the Retry-After header before sending another request. Monitor the X-RateLimit-Remaining-Second, X-RateLimit-Remaining-Minute, and X-RateLimit-Remaining-Hour headers to track your usage. You may also see ratelimit-limit, ratelimit-remaining, and ratelimit-reset headers, which reflect the per-second window. Before requesting a higher limit, consider batching, caching, filtering, or using webhooks to optimize your integration. If you notice a lower limit after sustained overage, this may indicate that a previous increase was reverted. For more details, see Rate Limits.

"I can't create another OAuth app / client_id": This is a separate cap — the number of OAuth applications per account is five — distinct from the request-rate limit above. If you need more, contact support with your use case.

5xx — server error: Retry with exponential backoff and jitter rather than immediately looping. Most 5xx errors are transient; if one endpoint fails repeatedly, include the x-request-id response header when you contact support. Exception: for a payment or reservation-altering request, check the actual resulting status first — don't blindly retry, or you risk double-charging a guest. More: Handling Failed Requests.

 

By symptom

If a reservation or listing does not appear in your search or list results, first check your filter and scope parameters. This is the most common cause. For recent records, allow time for synchronization, especially for reservations from channels like Airbnb, Vrbo, or Booking.com. This is specifically what GET /reservations-v3/search is for — confirm you're using it (with the right filter[...] params) rather than an older or narrower endpoint. If the record is still missing, contact support with the specific ID and the exact request you used.

If your webhook is not firing or you cannot subscribe to one, check the following: (1) Confirm you are subscribed to the correct v2 event name, as legacy and v2 webhooks are not interchangeable. (2) Ensure your endpoint returns a 2xx response, since Guesty will stop retrying if it does not. (3) On test or sandbox accounts, verify that the subscription was created successfully. Delivery may be delayed during periods of heavy load. The listing.calendar.updated event triggers only for direct edits to the calendar, rate, or minimum stay, not for new or changed reservations. To verify a webhook's authenticity, retrieve your endpoint's signing secret using GET /webhooks-v2/secret. For more information, see Webhooks Overview.

If you updated a listing's title or description through the API and don’t see the change on Airbnb, check whether the field was edited directly in Airbnb. If it was, Airbnb locks the field, and API updates will not sync until you unlock it in Airbnb. Updates using PUT /marketing/description-sets/{id} or POST /marketing/description-sets will not sync to Airbnb until the field is unlocked. Other channels like Booking.com and Vrbo may have similar requirements. For more information, see Marketing Fields and Translations.

GuestyPay returns 402 ERR_BAD_REQUEST: If the response includes "Request contradicts clearing interface configuration" or "Bad Bin or Host Disconnect," the GuestyPay account itself has a setup issue or is offline—this isn't something you can fix in your integration. Contact Customer Experience.

The error shape doesn't match what I saw on another endpoint: Expected — there's no single error envelope across the whole API. Though one pattern is the most common: a message nested under a single error key, e.g., GET /accounting-api/reservations/{id}/balance → {"error": {"message": "...", "status": 404}}. It's not universal, though — some endpoints are flat with message as an array of strings (GET /guest-folio/invoice-items → {"statusCode": 400, "message": [...]}), and some include their own body-level requestId field, separate from the x-request-id response header (GET /availability-pricing/api/calendar/listings/{id}). A good number of endpoints don't document an error body shape at all — only a text description. Check the specific endpoint's documented error schema rather than hardcoding one shape.

Do I need a "test account" or a "sandbox" account? Here is a quick rule of thumb: use a test account for almost all initial integration and development, unless you are specifically testing Stripe-related flows, in which case you need a sandbox. Use the production environment only when you are ready to go live with real data. Test accounts are the standard for new integration requests and work just like your production environment, just with separate test data. Sandboxes are separate environments (look for "sandbox" in the URL) used for Stripe integration testing because Guesty does not accept Stripe test keys in either production or regular test accounts. GuestyPay does not have any test environment—it runs live only, so you must use a real card for GuestyPay testing, regardless of which account type you are using.

A test account is a paid add-on and is separate from your production environment. Data does not transfer from production, so you will need to set up listings, reservations, and other information from scratch. To get a test account, contact your account manager.

 

MCP Server (Beta)

The Guesty MCP Server lets MCP-compatible AI assistants — currently Cursor, Claude Desktop, VS Code (Copilot), and Google Antigravity — read Guesty data through a controlled tool interface. It's read-only in beta: assistants can look up and summarize data, but can't create, update, or delete records yet. Tool coverage may still change before general availability.

 

Connecting

Currently, you can connect using either the local or hosted method. A fully managed deployment with credentials provisioned for you is not yet available.

  • Local (stdio, recommended): Run using npx -y @guestyorg/sdk mcp. You can use a BEARER_TOKEN environment variable for a static access token, or CLIENT_ID and CLIENT_SECRET environment variables. The MCP server will exchange these credentials for you, so no manual token step is required.
  • Hosted (HTTP, https://mcp.guesty.com/v1): Authenticate using an Authorization header at the start of the session, or use the set_token tool after connecting.

 

Troubleshooting

401 on every tool call: This indicates that no token was set. For hosted or HTTP connections, ensure you set the token using set_token or the Authorization header before using any other tool.

403, inconsistently: This error can occur with expired tokens or when OAuth clients have scopes for standard Open API access but not for MCP. First, re-authenticate with a new token. If the issue persists, confirm that the OAuth client has MCP scopes provisioned in addition to Open API v1 access.

Connected via Claude.ai (web), but no tools show up: Claude.ai web is not currently a supported client. Adding it as a URL-only connector causes it to default to OAuth discovery, which this server does not support. Use a supported client through stdio for full functionality.

Getting rate-limited, or repeated 401s after restarting the MCP: When using CLIENT_ID and CLIENT_SECRET, each restart requests a new token, which counts toward the 5-tokens-per-24-hours limit. To avoid this, reuse a cached token across restarts or use a static BEARER_TOKEN, which does not require re-exchange.

If reservation or journal-entry results appear incomplete, confirm that you are using the v3 Search Reservations tool, which supports filter[confirmationCode]. The legacy search tool is being deprecated and may not return all results. For journal-entry lookups (Get recognized journal entries / Get all journal entries), if you continue to see unexpected results, file a support ticket with detailed information.

I asked the assistant to create, update, or cancel something, and it didn't: Expected in beta — the MCP server is read-only for now.

 

Opening a support ticket

First, check your own system. Guesty cannot diagnose issues in external applications. If the problem might be in your code, have your web developer or technical vendor review it before contacting Guesty. If a marketplace partner built your integration, contact them first. They will reach out to Guesty if needed.

Once you have ruled out issues on your side, contact Customer Experience or use Live Chat. Both are available through the Guesty dashboard and Help Center. Providing context helps us resolve your issue faster, so include:

  • What you were trying to accomplish (the actual goal, not just the failing call — e.g., "sync a new reservation's payment status," not just "POST returned 422")
  • The steps that led to the error, in order, so support can reproduce it — not just the final failing request
  • When it happened — an exact timestamp if you have one, otherwise a date or date range; this is one of the most useful things you can provide
  • The full request URL and method in cURL format
  • The exact error message and status code
  • The x-request-id response header value
  • The x-gst-kong-dc header, if present (helps pinpoint which data center served the request)
  • Whether this is new behavior or has always failed
  • For MCP issues: which client and connection mode (stdio/HTTP), and whether auth was via BEARER_TOKEN, CLIENT_ID/CLIENT_SECRET, or set_token

 

For further reading

 

Was this article helpful?
0 out of 0 found this helpful