If you have a developer and software of your own — a website, an internal dashboard, a CRM — the TripWorks REST API lets that software read and update your account directly. You create an API key, decide what it's allowed to touch, and hand it to whoever is building the integration.
In this article
This article covers creating and scoping that key. The endpoint reference, with every field and example response, lives at api-docs.tripworks.com. It's public, so you can send it to a developer or an agency without giving them a TripWorks login.
Learn how to manage permission groups
In this article
- Whether the REST API is the right choice, or whether Zapier, webhooks, or an AI assistant fits better
- Creating an API key and choosing what it can reach
- Checking that the key works
- Rate limits, and what happens when you hit one
- What the API covers today, and what it doesn't
Is the REST API the right choice?
TripWorks has four ways to connect to other software. The REST API is the most capable, and the only one that needs a developer. Choosing the wrong one can cost weeks, so it's worth a minute up front.
The question that sorts it is who is doing the work.
- Your own software is doing the work. Use the REST API. It's the right answer for a custom booking page, a dashboard your team watches, or a sync into a system with no TripWorks connector of its own.
- You want something to happen automatically when a booking comes in. Use Zapier if you'd rather not write code, or webhooks if you're sending data to a system you control. Both are much quicker to set up than building against the API.
- A person wants to ask a question or make a quick change. Use an AI assistant. No code, and it follows that person's own permissions.
An API key is a standing credential for software. Nobody approves each request, and it keeps working until you deactivate it. That's exactly what an integration needs, and exactly why the scopes you grant matter.
Create an API key
If you lose the key
You can't look it up again. TripWorks stores only a one-way fingerprint and the last four characters, so nobody — including TripWorks support — can recover the original value. Use Rotate on the Keys tab to issue a replacement, then update wherever the old one was stored. Rotating invalidates the previous key immediately, so pick a quiet moment.
Check that it works
Your developer sends the key as a bearer token on every request:
curl https://your-account.tripworks.com/rest/locations \
-H "Authorization: Bearer tw_your_key_here"
Replace your-account with your own TripWorks subdomain, the one you log in at. Your account is identified by that subdomain, so there's no account ID to pass anywhere.
A working request returns your locations with a meta block:
{
"success": true,
"locations": [ ... ],
"meta": { "per_page": 25, "has_more": false, "next_cursor": null }
}
That's the confirmation the key is live and correctly scoped. A 401 instead almost always means the header isn't exactly Authorization: Bearer tw_… — a missing Bearer prefix is the single most common cause.
What the API covers
The API spans most of what you work with day to day: bookings, trips, customers, experiences, locations, promo codes, restrictions, gift cards, resellers, reviews, trip notes, trip sources, waiver types, your team, your manifest, your audit log, phone calls, saved reports, and aggregate analytics.
Most of those can be read, created, updated and deleted. A few are read-only by design.
What isn't available yet: live availability, payment records, and the full sell flow — checking availability, holding a slot and taking payment end to end. If your project depends on selling through the API rather than through a TripWorks booking page or widget, that isn't possible today. Better to know before you scope the work.
New resources are added regularly, and api-docs.tripworks.com is generated from the live API, so it's always an accurate list of what exists right now.
Rate limits
Limits are counted per key rather than per IP address, so an agency working from one office doesn't get throttled because a colleague is also calling the API.
| Limit | Allowance |
|---|---|
| Reads per minute | 200 |
| Writes per minute | 65 |
| Reads per hour | 3,000 |
| Writes per hour | 1,000 |
| All requests per minute, whole account | 400 |
Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, so a well-built integration can pace itself rather than waiting to be refused. Going over returns a 429 with a Retry-After header telling you how many seconds to wait.
The last row is the one that catches people out. That 400-per-minute ceiling is shared by every key on the account, so a noisy new integration can slow down one that had been running happily for months. When you add a second integration, watch the Limits tab for a few days.
Reading lists
List endpoints return 25 records at a time, and there's no way to ask for more. Rather than page numbers, each response includes a next_cursor; passing it back gets you the next 25.
GET /rest/customers?per_page=25
GET /rest/customers?cursor=eyJpZCI6MTIzfQ
There's deliberately no total count. On an account with hundreds of thousands of customers, counting them all on every request would be slow for everyone, so use has_more to decide whether to keep going.
Filtering puts the operator in brackets after the field name, and sorting takes a - prefix for descending order:
GET /rest/experiences?name[contains]=Sunset&sort=-created_at
When something goes wrong
Every error comes back in the same shape, with a code your developer can branch on instead of matching on text:
{
"success": false,
"message": "Rate limit exceeded.",
"error": { "code": "too_many_requests" }
}
| What you see | What it usually means |
|---|---|
401 unauthorized |
The Authorization header is missing or malformed |
403 forbidden |
The key was rotated or deactivated, or the REST API integration is switched off |
403 insufficient_scope |
The key is valid but wasn't granted this area — check the Keys tab |
422 unknown_fields |
The request body includes a field that can't be written |
422 invalid_cursor |
A cursor was reused after the sort changed, or it's gone stale — start the list again |
429 too_many_requests |
Slow down; Retry-After says by how much |
The Logs tab shows recent API activity on your account, which is usually faster than asking a developer to reproduce something.
Two examples
A dashboard on the office wall. A multi-location operator wants today's numbers on a screen in the back office. Their developer creates a key named "Ops dashboard" with Read on bookings, trips and analytics, and nothing else. Even if that key leaked, it couldn't change anything.
Customers into a CRM. A tour company syncs new customers into their marketing CRM overnight. The key has Read on customers and nothing more, it pages through with the cursor, and it runs at 2am so it isn't competing with the booking widget for the account's request budget.
Frequently asked questions
Next steps
- Share api-docs.tripworks.com with whoever is building the integration
- Set up webhooks if your system needs telling when something happens, rather than polling for it
- Try an AI assistant if what you actually wanted was to ask questions about your data
Built for attractions, tours & activities
Build on top of your booking data
See how attractions, tours, and activities connect TripWorks to their own websites, dashboards, and internal tools. Book a demo and make the switch.