Partner API
The Partner API is a venue-scoped, read-only REST API for bookings, transactions and contacts. Use it to copy Alba data into another system without giving that system permission to change anything in Alba.
Base URL
https://api.albaplay.com/api/v1
Authentication
Send your API key in the X-Api-Key header on every request. Keys begin with alba_sk_ . There is no OAuth flow, bearer token or query-parameter form of the key.
Account Owner, Account Admin and Location Admin create keys under Settings → API keys after accepting the API terms for the venue. See How to create and manage API keys. The full key is shown once and cannot be retrieved later. If it is lost, revoke it and create a replacement.
curl "https://api.albaplay.com/api/v1/bookings?limit=2" \\ -H "X-Api-Key: alba_sk_your_key"
A missing, malformed, unknown or revoked key returns 401 unauthorized . Unknown and revoked keys return the same response on purpose.
Venue scoping
Each key belongs to exactly one venue. The optional facility_id parameter is a guard, not a venue selector. It must match the venue attached to the key. A different venue returns 403 forbidden .
Shared query parameters
Bookings, transactions and contacts accept the same parameters:
modified_since: inclusive lower bound onmodified_at. Use an ISO 8601 timestamp withZor an explicit offset, such as2026-02-28T00:00:00Z.cursor: opaque cursor from the previous page. Pass it back unchanged.limit: page size from 1 to 200. The default is 100.contact_id: restricts results to one contact.facility_id: verifies that the key belongs to the expected venue.
Pagination
Every list response contains data and next_cursor . There is no total count. Results are ordered by modified_at ascending, then id ascending. That order cannot be changed.
{
"data": [...],
"next_cursor": "opaque-value-or-null"
}
- Call the endpoint without
cursor. - Upsert every record in
databyid. - Pass
next_cursorback ascursor. - Stop only when
next_cursorisnull.
A short or empty page is not an end signal on its own. Do not decode, construct or modify a cursor. Store it as a string and return it unchanged.
Keep modified_since and contact_id fixed until the cursor reaches the end. To change a filter, restart without a cursor. You may change limit between pages.
Incremental sync
Run a historical backfill with limit=200 , walk every page, then poll every 15 to 60 minutes. Set modified_since to the highest modified_at you have seen, minus five minutes of overlap.
Repeated records are expected. Upsert by id . When deleted_at is non-null, treat the record as a tombstone and remove your copy.
A contact_id from bookings or transactions does not always resolve on the contacts endpoint. Treat that as “not a current customer of this venue”, not as a failed sync.
A timestamp without a timezone, or an impossible calendar date, returns 400 invalid_param .
Bookings
GET https://api.albaplay.com/api/v1/bookings
Returns confirmed and cancelled bookings for the venue attached to the API key. Pending and aborted bookings are not included.
id: stable booking UUID. Upsert on this value.contact_id: booking owner UUID, ornull. It may not resolve on the contacts endpoint.facility_id: the venue UUID.status:confirmedorcancelled.title: custom drop-in title when set; otherwise the bay or simulator names (checkout add-ons such as rental clubs are not included); otherwise the venue name. It is never empty.start_atandend_at: overall booking period in UTC.player_count: number of players.resources: bays, simulators and other resources on this booking. Each object hasid(resource UUID),name,type(lower-case Alba resource type, such assimorcheckout_addon),start_atandend_at(that resource's window in UTC). Back-to-back rows on the same resource are merged into one window. Usetypeto filter, for examplesimfor bays only. Cancelled and soft-deleted bookings still include the resources they held.created_atandmodified_at: creation and last-change timestamps. Moving a booking to another bay at the same times updatesmodified_at.deleted_at: non-null for a soft-deleted booking. Remove your copy.
If you already sync bookings, run a one-time backfill to populate resources on older records. Incremental sync only returns the new field when a booking appears in the feed again.
curl "https://api.albaplay.com/api/v1/bookings?modified_since=2026-01-01T00:00:00Z&limit=2" \\ -H "X-Api-Key: alba_sk_your_key"
Transactions
GET https://api.albaplay.com/api/v1/orders
In Alba this is what you see as Transactions. The HTTP path is GET /api/v1/orders .
One transaction is one captured payment at the key’s venue. Payments that were never captured are not returned. Refunds update the original transaction instead of creating a negative one.
id: stable transaction UUID.contact_id: purchaser UUID, ornull.facility_id: the venue UUID.reference: opaque Alba correlation reference.category: opaque classification of what was paid for. New values may appear.currency: ISO 4217 currency code.total_amount_minorandrefunded_amount_minor: amounts in the currency’s minor unit.payment_status:paid,partially_refundedorrefunded.tax_amount_minoranddiscount_amount_minor: may benullwhen no line-item data exists.line_items: purchased items, possibly empty for older transactions.ordered_at: use this for revenue reporting.modified_at: use this only as the sync watermark.
Convert amounts using the exponent for the transaction’s own currency. Do not always divide by 100. NOK 249.50 is 24950 , while ISK 1000 is 1000 .
A refund changes refunded_amount_minor , payment_status and modified_at . The transaction then appears again in an incremental sync.
Line amounts are not guaranteed to sum exactly to the captured total. Line tax amounts do sum to the transaction tax amount when line data exists. Each line can contain id , kind , description , quantity , unit_amount_minor , amount_minor , tax_amount_minor , tax_percent , booking_id and sim_id .
curl "https://api.albaplay.com/api/v1/orders?modified_since=2026-01-01T00:00:00Z&limit=1" \\ -H "X-Api-Key: alba_sk_your_key"
Contacts
GET https://api.albaplay.com/api/v1/contacts
Returns people the venue counts as customers: anyone with a confirmed booking, a membership or a voucher at that venue. Marketing consent alone, cancelled-only booking history, and pending or abandoned bookings do not make someone a contact.
id: stable person UUID.facility_ids: always an array with exactly the key’s venue.first_name,last_name,email,phoneanddate_of_birth: nullable personal data.language: preferred language.email_on: the venue’s newsletter opt-in.created_at,modified_atanddeleted_at: lifecycle timestamps.
email_on is false both when someone declined and when no consent was recorded. Use it only to gate email marketing. There is no SMS consent field. A newsletter-consent change does not update modified_at by itself, so re-read a contact by contact_id before a marketing send.
A deleted contact remains in the feed as a tombstone: deleted_at is set, personal fields are null , and email_on is false. Remove any stored personal data when you receive this record.
A valid UUID with no matching contact returns an empty page.
curl "https://api.albaplay.com/api/v1/contacts?modified_since=2026-01-01T00:00:00Z&limit=2" \\ -H "X-Api-Key: alba_sk_your_key"
Errors
Documented endpoints return errors in one JSON shape. Branch on error.code , not on the human-readable message.
{
"error": {
"code": "invalid_param",
"message": "limit must be an integer between 1 and 200",
"param": "limit"
}
}
401 unauthorized: missing, malformed, unknown or revoked API key.403 forbidden: the key lacks read scope, orfacility_idbelongs to another venue.400 invalid_param: a query parameter failed validation.paramnames it.429 rate_limited: the key’s request budget is exhausted.500 internal: unexpected server error. Includes arequest_idfor Alba support.
Error bodies never contain SQL, stack traces or data from another venue. An unknown route or unsupported method under /api/v1 may return a plain 404 rather than this JSON envelope.
- Stop and alert a person on 401 or 403.
- Fix the request on 400. Do not retry it unchanged.
- Follow
Retry-Afteron 429. - Retry 500 errors with exponential backoff using the same cursor.
Rate limits
Each API key has a budget of 60 requests per 60-second window, shared across bookings, transactions and contacts. The budget follows the key, not the caller’s IP address. Design for 60 requests per minute.
RateLimit: "60-in-1min"; r=41; t=37 RateLimit-Policy: "60-in-1min"; q=60; w=60
r: requests remaining in the current window.t: seconds until the window resets.Retry-After: seconds to wait, sent on a 429 response.
Only authenticated requests reach the limiter. Walk pages sequentially with limit=200 . If you are throttled, wait for Retry-After , then retry the same request unchanged.