Musafy Websites & bookings for travel agencies Sign in Start free
Developers

One versioned API. Scoped keys. Signed webhooks.

Everything the dashboard does, the API does — it is the same surface. Keys carry their own scopes, their own rate limit and a pinned version, so an integration upgrades when its author is ready and not when we ship.

Included from Growth REST · JSON /api/v1

How a request finds your agency

Resolved in this order.

A key names its own agency and is checked first, so one agency's key can never act on another's data.

SourceUsed by
HostPublic storefront requests
Authorization: Bearer sk_…API keys and integrations
X-Tenant-IDDashboard, for agencies you belong to
X-Request-IDYours, echoed back and kept on the audit trail
One error envelope

Always this shape.

Field errors arrive keyed by field, and every failure carries the request id you can quote at us.

{
  "error": {
    "code": "tenant_suspended",
    "detail": "This account is suspended.",
    "request_id": "…",
    "fields": { "slug": ["That name is taken."] }
  }
}
StatusWhen
400Validation failed, or a bad one-time code
401 / 403Not signed in · not a member · missing a permission
402The agency is suspended
409Slug taken · seats sold out · coupon exhausted · publish pre-flight failed
429Rate limited or a code re-sent too soon — carries the wait

Seats and coupons are claimed with a single conditional write rather than read-then-write, so two simultaneous bookings cannot both take the last bed — one of them gets the 409.

The surface, in groups

Six places to work.

Catalogue

/catalogue/packages/ · hotels · flights · prices · itinerary · discounts · /catalogue/visa-options/ · /catalogue/visa-applications/

Creating a package accepts the whole graph in one call — the same service the sign-up wizard uses.

CRM

/crm/enquiries/ · /crm/leads/{id}/transition/ · /crm/quotes/ · /crm/bookings/{id}/confirm/ · /crm/coupons/validate/

Stages move through action endpoints, never a field write, so the timeline cannot be bypassed.

Site & comms

/website/domains/{id}/verify/ · /website/revisions/{id}/restore/ · /comms/providers/{id}/send-test/ · /comms/templates/ · /seo/redirects/

Credentials come back masked, never as values — saving them is one way.

Keys, hooks & data

/apps/keys/ · /apps/webhooks/{id}/rotate-secret/ · /apps/deliveries/ · /apps/data-jobs/ · /billing/usage/

A new key's raw value is shown once. Deliveries log status, attempts and duration.

Public, no key

POST /public/enquiries/

For a form on your own site. The agency comes from the host, never the payload, and it is throttled by address.

Custom fields

/catalogue/metafield-definitions/ · /catalogue/metafields/

Typed fields on packages, visas, customers, bookings and pages — added without a migration, and optionally published to your storefront.

Webhooks that keep trying

Subscribe to booking, lead and visa events. Each delivery is signed, retried with backoff and logged; the secret rotates on demand, and the subscription pins a payload version so an old integration keeps receiving the shape it was written against.

Import and export as jobs

CSV in and out for packages, customers and bookings, with the exact headers published, a row count and an error report for what didn't load. Big imports run in their own lane so they cannot delay anyone's booking confirmation.

Version history you can call

Pages, packages, visa options and theme settings are snapshotted on change and restorable in one call — and the restore is itself recorded as a version.