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 on modified_at   . Use an ISO 8601 timestamp with Z    or an explicit offset, such as 2026-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"
}
  1. Call the endpoint without cursor   .
  2. Upsert every record in data    by id   .
  3. Pass next_cursor    back as cursor   .
  4. Stop only when next_cursor    is null   .

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, or null   . It may not resolve on the contacts endpoint.
  • facility_id   : the venue UUID.
  • status   : confirmed    or cancelled   .
  • 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_at    and end_at   : overall booking period in UTC.
  • player_count   : number of players.
  • resources   : bays, simulators and other resources on this booking. Each object has id   (resource UUID), name   , type   (lower-case Alba resource type, such as sim   or checkout_addon   ), start_at   and end_at   (that resource's window in UTC). Back-to-back rows on the same resource are merged into one window. Use type   to filter, for example sim   for bays only. Cancelled and soft-deleted bookings still include the resources they held.
  • created_at    and modified_at   : creation and last-change timestamps. Moving a booking to another bay at the same times updates modified_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, or null   .
  • 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_minor    and refunded_amount_minor   : amounts in the currency’s minor unit.
  • payment_status   : paid   , partially_refunded    or refunded   .
  • tax_amount_minor    and discount_amount_minor   : may be null    when 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   , phone    and date_of_birth   : nullable personal data.
  • language   : preferred language.
  • email_on   : the venue’s newsletter opt-in.
  • created_at   , modified_at    and deleted_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, or facility_id    belongs to another venue.
  • 400 invalid_param   : a query parameter failed validation. param    names it.
  • 429 rate_limited   : the key’s request budget is exhausted.
  • 500 internal   : unexpected server error. Includes a request_id    for 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-After    on 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.

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.

Still need help? Contact Us Contact Us