TableFai

Utvecklare

TableFais partner-API

För en restaurangs egen webbplats, dess byrå, ett kassasystem eller en AI-agent: läs lediga tider, håll ett bord, boka åt en gäst och följ varje bokning, med samma motor och regler som tablefai.com. Ingen provision och ingen avgift per bokning.

TableFai partner API, version 1.0.0 · OpenAPI-dokumentet (JSON)

Kom igång på fem minuter

  1. Restaurangens ägare eller administratör skapar en nyckel under Ställets inställningar → Webbplats och länkar → API-nycklar, med de behörigheter ni behöver. Den visas en gång.

  2. Kontrollera nyckeln: stället, dess sittningar och villkor.

    export TABLEFAI_KEY=tf_live_…
    curl https://tablefai.com/api/partner/v1/venue \
      -H "Authorization: Bearer $TABLEFAI_KEY"
  3. Hitta en ledig tid för sällskapet.

    curl "https://tablefai.com/api/partner/v1/availability?date=2026-12-04&party=2" \
      -H "Authorization: Bearer $TABLEFAI_KEY"
  4. Håll den: bordet hålls i tio minuter.

    curl -X POST https://tablefai.com/api/partner/v1/holds \
      -H "Authorization: Bearer $TABLEFAI_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{"date": "2026-12-04", "time": "19:00", "party": 2}'
  5. Boka det hållna bordet åt gästen: gästen får TableFais bekräftelse med sin hanteringslänk.

    curl -X POST https://tablefai.com/api/partner/v1/bookings \
      -H "Authorization: Bearer $TABLEFAI_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{"hold": "<the hold's id>", "guest": {"name": "Ada Lind", "phone": "+46701234567", "email": "ada@example.se"}, "consent": {"terms": true}}'
  6. Följ sedan varje bokning när den händer: Webhooks

Autentisering

Varje anrop utom OpenAPI-dokumentet skickar ställets nyckel som bearer-token. En nyckel hör till ett ställe, visas en gång och kan återkallas när som helst (då 401).

Authorization: Bearer tf_live_…

Varje nyckel har de behörigheter den fått; ett anrop utanför dem ger 403 scope:

  • availability:read — Läsa lediga tider och placering
  • bookings:read — Läsa ställets bokningar
  • bookings:write — Hålla bord, boka och avboka

A key of the venue: tf_live_ and 43 characters.

Gränser

120 anrop per minut och nyckel; över det 429 rate_limited.

  • X-RateLimit-Limit, X-RateLimit-Remaining — på varje svar: gränsen och vad som är kvar av den denna minut
  • Retry-After — vid 429: sekunder tills nyckeln får anropa igen
  • Idempotency-Key — ett UUID på POST holds och POST bookings: samma nyckel ger samma hållna bord eller bokning igen

Svar och fel

Svaren är JSON i data; ett fel är en stabil kod med HTTP-status, och validering anger varje fälts regel (koder, aldrig meningar).

{"error": {"code": "validation", "fields": {"date": ["date_format"]}}}
  • errorobjectkrävs
    • codestringkrävs
    • fieldsobject

      validation: the rule codes per field

API:ets egna anteckningar (engelska)

TableFai's partner API lets a restaurant's own systems — its developer's or agency's website, a POS, an AI agent — read the venue's availability and seating, hold tables, book for a guest, read and sync the venue's bookings and cancel them, with the same engine and rules as tablefai.com. There is no commission and no per-booking fee.

Authentication. Every call except this document sends Authorization: Bearer tf_live_…: a key the venue's owner or admin makes under Venue → Website & links → API keys. A key belongs to one venue (the venue every call works on), is shown once when it is made and can be revoked at any time (then 401). TableFai keeps only its SHA-256.

Scopes. availability:read (availability, seating), bookings:read (the venue's bookings), bookings:write (holds, bookings, cancellations). Every key reads its venue. A call outside the key's scopes is 403 scope with the scope it needs in required.

Limits. 120 requests a minute per key; above it 429 rate_limited with Retry-After (seconds). Every answer carries X-RateLimit-Limit and X-RateLimit-Remaining.

Plan. The partner API and webhooks are part of TableFai's Pro plan. While the venue's company is on Start, every call answers 402 plan_required (feature: api_keys, plan: pro); the key is kept and works again with Pro. While the company's subscription is paused or canceled, GET venue and GET bookings… still answer and every other call is 402 subscription_inactive (status).

Answers. JSON in {"data": …} (a page adds meta); errors are {"error": {"code": …}} with the HTTP status, validation errors {"error": {"code": "validation", "fields": {"<field>": ["<rule>"]}}} (codes, never sentences). Every answer has an X-Request-Id. Dates (date, from, to) and times (time, HH:MM) are the venue's, in its timezone; a booking's moments (starts_at, ends_at) carry their offset; other timestamps are UTC (…Z). Texts the restaurant writes come as {text, locale} in the language asked for with ?locale= (en, sv), else the venue's.

Booking. GET availability → GET seating (when the service lets guests choose) → POST holds (the tables are kept ten minutes) → POST bookings with the hold and the guest. POST holds and POST bookings take an Idempotency-Key (a UUID): the same key answers the same hold or booking again; another request under it is 422 idempotency_mismatch. The venue must be published (else 409 not_published). The guest gets TableFai's confirmation mail with their manage link, as when they book on tablefai.com.

Webhooks. The venue's owner or admin adds an https address under Website & links → Webhooks and gets its signing secret (whsec_…) once. TableFai POSTs booking.created, booking.updated and booking.cancelled (and ping) — see webhooks — with TableFai-Event, TableFai-Delivery and TableFai-Signature: t=<unix seconds>, v1=<hex HMAC-SHA256 of "<t>.<body>" with the whole secret as the key>. Check the signature over the raw body and refuse a t more than five minutes away. Answer 2xx within 10 seconds; anything else is tried again after 1 min, 5 min, 30 min, 2 h, 6 h and 24 h, then given up; a webhook failing for three days is turned off. Redirects are not followed. Deliveries may come more than once and out of order: use the event id, and the booking's version or updated_at.

Venue

GET /venue

The key's venue

Its name, page, timezone, languages, party limits, running services with their seating modes, policies, and the key itself. Any scope.

Parametrar

Parametrar
NamnITypOm
localefrågastringthe language of the restaurant's textsVärden: en, sv

Svar

  • 200The venue.
    Huvuden: X-RateLimit-Limit, X-RateLimit-Remaining
    Svarets fält ({data: Venue})
    • dataVenuekrävs
      • idstringkrävs
      • namestringkrävs
      • slugstringkrävs
      • publishedbooleankrävs
      • urlstring (uri)krävs
      • countrystringkrävs

        ISO 3166-1 alpha-2

      • timezonestringkrävs
      • currencystringkrävs

        ISO 4217

      • default_localestringkrävs
      • localesarray of stringkrävs
      • addressAddresskrävs
        • streetstring | nullkrävs
        • postal_codestring | nullkrävs
        • citystring | nullkrävs
        • countrystringkrävs
      • phonestring | nullkrävs
      • booking_phonestring | nullkrävs
      • emailstring | nullkrävs
      • websitestring | nullkrävs
      • party_limitsPartyLimitskrävs

        The party sizes bookable online.

        • minintegerkrävs
        • maxintegerkrävs
      • servicesarray of Servicekrävs
        • idstringkrävs
        • nameText | nullkrävs
          • textstringkrävs
          • localestringkrävs
            Värden: en, sv
        • weekdaysarray of integer (1–7)krävs

          ISO weekdays, Monday 1

        • startsstringkrävs
        • endsstringkrävs
        • last_seatingstringkrävs
        • modestringkrävs

          request: bookings wait for the restaurant (status requested)

          Värden: auto, request
        • seatingstringkrävs

          the seating choice a hold may make

          Värden: none, area, type, table
      • policiesobjectkrävs
        • cancellation_hoursintegerkrävs
        • late_grace_minutesintegerkrävs
        • no_show_fee_minorinteger | nullkrävs
        • deposit_minorinteger | nullkrävs
        • textText | nullkrävs
          • textstringkrävs
          • localestringkrävs
            Värden: en, sv
      • keyobjectkrävs

        The key this call was made with.

        • idstringkrävs
        • namestringkrävs
        • prefixstringkrävs

          the key's first 12 characters

        • scopesarray of stringkrävs
          Värden: availability:read, bookings:read, bookings:write
  • 401No key, an unknown or a revoked key (unauthenticated).
    Huvuden: WWW-Authenticate
  • 402plan_required (feature, plan: the venue's company is on the Start plan) or subscription_inactive (status: its subscription is paused or canceled).
  • 403scope (the key lacks the scope in required) or company_suspended.
  • 429rate_limited: more than 120 requests in a minute (retry_after in seconds).
    Huvuden: Retry-After

Availability

GET /availability

A date's free times (availability:read)

Parametrar

Parametrar
NamnITypOm
datekrävsfrågastring (date)Exempel: 2026-12-02
partykrävsfrågainteger (1–50)
localefrågastringthe language of the restaurant's textsVärden: en, sv

Svar

  • 200The date's services and slots.
    Huvuden: X-RateLimit-Limit, X-RateLimit-Remaining
    Svarets fält ({data: Availability})
    • dataAvailabilitykrävs

      The date's open services and their slots by the venue's online rules; nothing but whether a slot is free.

      • datestring (date)krävs
      • partyintegerkrävs
      • party_limitsPartyLimitskrävs

        The party sizes bookable online.

        • minintegerkrävs
        • maxintegerkrävs
      • large_partyobject | nullkrävs
        • textText | nullkrävs
          • textstringkrävs
          • localestringkrävs
            Värden: en, sv
        • phonestring | nullkrävs
      • servicesarray of objectkrävs
        • idstringkrävs
        • nameText | nullkrävs
          • textstringkrävs
          • localestringkrävs
            Värden: en, sv
        • slotsarray of Slotkrävs
          • timestringkrävs
          • availablebooleankrävs
          • offerOffer | nullkrävs

            The best of the restaurant's own offers this time has (given at the till; payments are unaffected), or null.

        • preorderstringkrävs

          Whether the service takes pre-orders (slice 8b). A `required` one cannot be booked through this API: its holds answer 409 `preorder_required`.

          Värden: off, optional, required
        • verificationstringkrävs

          Whether the service asks a party of this size to verify with BankID on TableFai's own pages (Verifierad gäst, slice 8b); such a party cannot be booked through this API: its holds answer 409 `verification_required`.

          Värden: none, bankid
        • waitlistbooleankrävs

          Whether a guest with a party of this size may join the venue's online waitlist for this service on TableFai's own pages (slice 9a): its waitlist is on, the party is within its online sizes, and a service with a guarantee can take payments. This API takes no waitlist requests.

      • nextarray of NextSlotkrävs

        the next three free slots of the 30 days after, when the date has none

        • datestring (date)krävs
        • timestringkrävs
  • 401No key, an unknown or a revoked key (unauthenticated).
    Huvuden: WWW-Authenticate
  • 402plan_required (feature, plan: the venue's company is on the Start plan) or subscription_inactive (status: its subscription is paused or canceled).
  • 403scope (the key lacks the scope in required) or company_suspended.
  • 409not_published: the venue's page is not published, so it takes no online bookings.
  • 422validation with fields, or another refusal of the request (idempotency_mismatch, seating_unavailable, table_too_large).
  • 429rate_limited: more than 120 requests in a minute (retry_after in seconds).
    Huvuden: Retry-After

GET /seating

The seating choice at a time (availability:read)

Parametrar

Parametrar
NamnITypOm
datekrävsfrågastring (date)Exempel: 2026-12-02
timekrävsfrågastringHH:MM on the 15-minute gridExempel: 19:00
partykrävsfrågainteger (1–50)
localefrågastringthe language of the restaurant's textsVärden: en, sv

Svar

  • 200By the service's seating mode.
    Huvuden: X-RateLimit-Limit, X-RateLimit-Remaining
    Svarets fält ({data: Seating})
    • dataSeatingkrävs

      What a guest may choose at a date, time and party, by the service's seating mode.

  • 401No key, an unknown or a revoked key (unauthenticated).
    Huvuden: WWW-Authenticate
  • 402plan_required (feature, plan: the venue's company is on the Start plan) or subscription_inactive (status: its subscription is paused or canceled).
  • 403scope (the key lacks the scope in required) or company_suspended.
  • 409not_published: the venue's page is not published, so it takes no online bookings.
  • 422validation with fields, or another refusal of the request (idempotency_mismatch, seating_unavailable, table_too_large).
  • 429rate_limited: more than 120 requests in a minute (retry_after in seconds).
    Huvuden: Retry-After

Holds

POST /holds

Keep tables ten minutes (bookings:write)

Parametrar

Parametrar
NamnITypOm
Idempotency-Keykrävshuvudstring (uuid)a UUID: the same key answers the same hold or booking again
localefrågastringthe language of the restaurant's textsVärden: en, sv

Kropp HoldRequest

  • datestring (date)krävs
  • timestringkrävs

    on the 15-minute grid

  • partyinteger (1–50)krävs
  • seatingSeatingChoice

    none lets the restaurant choose; another mode must be the service's own.

    • modestringkrävs
      Värden: none, area, type, table
    • zonestring

      area: the zone

    • tagstring

      type: the kind of table

      Värden: window, booth, sofa, quiet, view, outdoor, bar, high_top, private, accessible, high_chair, near_entrance
    • tablestring

      table: the table

Svar

  • 201The hold.
    Huvuden: X-RateLimit-Limit, X-RateLimit-Remaining
    Svarets fält ({data: object})
    • dataobjectkrävs
      • holdHoldkrävs
        • idstringkrävs
        • expires_atstring (date-time)krävs

          ten minutes after it was made

        • tableTableRef | nullkrävs
          • idstringkrävs
          • codestringkrävs
        • zoneZone | nullkrävs
          • idstringkrävs
          • nameText | nullkrävs
          • colorstringkrävs
  • 401No key, an unknown or a revoked key (unauthenticated).
    Huvuden: WWW-Authenticate
  • 402plan_required (feature, plan: the venue's company is on the Start plan) or subscription_inactive (status: its subscription is paused or canceled).
  • 403scope (the key lacks the scope in required) or company_suspended.
  • 409slot_taken (with alternatives: [{date, time}]), not_published, invalid_transition (with from, to), stale, payment_required: the service takes a card guarantee, a deposit or a prepaid menu, which only TableFai's own booking pages take (the guest books there), preorder_required (the service needs a pre-order) or verification_required (the service asks the party to verify with BankID, slice 8b).
  • 422validation with fields, or another refusal of the request (idempotency_mismatch, seating_unavailable, table_too_large).
  • 429rate_limited: more than 120 requests in a minute (retry_after in seconds).
    Huvuden: Retry-After

DELETE /holds/{id}

Give a hold's tables back (bookings:write)

Parametrar

Parametrar
NamnITypOm
idkrävssökvägstringExempel: 01JC9Y7F3K2M8Q4R6T0V1W2X3Y

Svar

  • 204Released (also when there was nothing to release).
  • 401No key, an unknown or a revoked key (unauthenticated).
    Huvuden: WWW-Authenticate
  • 402plan_required (feature, plan: the venue's company is on the Start plan) or subscription_inactive (status: its subscription is paused or canceled).
  • 403scope (the key lacks the scope in required) or company_suspended.
  • 429rate_limited: more than 120 requests in a minute (retry_after in seconds).
    Huvuden: Retry-After

Bookings

GET /bookings

The venue's bookings (bookings:read)

50 a page. Without updated_since by start; with it, the bookings changed at or after it, in the order they changed (sync by the last updated_at you saw).

Parametrar

Parametrar
NamnITypOm
fromfrågastring (date)the first date (the venue's)Exempel: 2026-12-02
tofrågastring (date)the last dateExempel: 2026-12-02
statusfrågastringone status or several, comma-separatedExempel: confirmed,seated
updated_sincefrågastring (date-time)ISO 8601; without a zone UTC
pagefrågainteger (≥ 1)
localefrågastringthe language of the restaurant's textsVärden: en, sv

Svar

  • 200A page of bookings.
    Huvuden: X-RateLimit-Limit, X-RateLimit-Remaining
    Svarets fält ({data: array of Booking})
    • dataarray of Bookingkrävs
      • referencestringkrävs
      • statusstringkrävs
        Värden: requested, confirmed, waitlisted, arrived, seated, finished, no_show, cancelled_guest, cancelled_venue
      • datestring (date)krävs

        the service's date (a booking after midnight belongs to the evening before)

      • timestringkrävs
      • endstringkrävs
      • minutesintegerkrävs
      • partyintegerkrävs
      • starts_atstring (date-time)krävs

        with the venue's offset

      • ends_atstring (date-time)krävs
      • serviceobject | nullkrävs
        • idstringkrävs
        • nameText | nullkrävs
          • textstringkrävs
          • localestringkrävs
            Värden: en, sv
      • tablesarray of TableRefkrävs
        • idstringkrävs
        • codestringkrävs
      • seatingobjectkrävs

        the guest's seating choice {mode, zone?, tag?, table?}

      • sourcestringkrävs
        Värden: widget, site_link, qr, instagram, facebook, google, email, marketplace, api, phone, walk_in, staff, app, import
      • source_originstring | nullkrävs
      • utmobject | nullkrävs
        • sourcestring | nullkrävs
        • mediumstring | nullkrävs
        • campaignstring | nullkrävs
      • guestobject | nullkrävs
        • namestringkrävs
        • phonestring | nullkrävs
        • emailstring | nullkrävs
      • localestringkrävs
      • occasionstring | nullkrävs
        Värden: birthday, anniversary, date_night, business, celebration, other
      • accessibilityarray of stringkrävs
        Värden: wheelchair, step_free, walking_aid, hearing, vision, service_dog, high_chair, pram
      • requestsstring | nullkrävs
      • allergiesstring | nullkrävs
      • confirmed_atstring (date-time) | nullkrävs
      • late_minutesinteger | nullkrävs
      • cancelled_latebooleankrävs

        cancelled by the guest inside the cancellation window

      • status_atstring (date-time) | nullkrävs
      • created_atstring (date-time)krävs
      • updated_atstring (date-time)krävs
      • versionintegerkrävs

        grows with every change

    • metaMetakrävs
      • pageintegerkrävs
      • pagesintegerkrävs
      • totalintegerkrävs
  • 401No key, an unknown or a revoked key (unauthenticated).
    Huvuden: WWW-Authenticate
  • 402plan_required (feature, plan: the venue's company is on the Start plan) or subscription_inactive (status: its subscription is paused or canceled).
  • 403scope (the key lacks the scope in required) or company_suspended.
  • 422validation with fields, or another refusal of the request (idempotency_mismatch, seating_unavailable, table_too_large).
  • 429rate_limited: more than 120 requests in a minute (retry_after in seconds).
    Huvuden: Retry-After

POST /bookings

Book a hold for a guest (bookings:write)

The hold becomes the booking in one transaction (confirmed, or requested in a service in request mode); source api. The guest is mailed the confirmation with their manage link.

Parametrar

Parametrar
NamnITypOm
Idempotency-Keykrävshuvudstring (uuid)a UUID: the same key answers the same hold or booking again
localefrågastringthe language of the restaurant's textsVärden: en, sv

Kropp BookingRequest

  • holdstringkrävs
  • guestobjectkrävs
    • namestring (≤ 120)krävs
    • phonestring (≤ 40)krävs

      E.164, or a national number of the venue's country

    • emailstring (email, ≤ 190)krävs
    • localestring | null
      Värden: en, sv
  • occasionstring | null
    Värden: birthday, anniversary, date_night, business, celebration, other
  • requestsstring (≤ 2000) | null
  • allergiesstring (≤ 2000) | null
  • accessibilityarray of string | null
    Värden: wheelchair, step_free, walking_aid, hearing, vision, service_dog, high_chair, pram
  • consentobjectkrävs
    • termstruekrävs

      the guest accepted the booking terms and the venue's policy

    • marketingboolean

Svar

  • 201The booking.
    Huvuden: X-RateLimit-Limit, X-RateLimit-Remaining
    Svarets fält ({data: object})
    • dataobjectkrävs
      • bookingBookingkrävs

        A booking as the venue sees it, without its staff's own notes and tags.

        • referencestringkrävs
        • statusstringkrävs
          Värden: requested, confirmed, waitlisted, arrived, seated, finished, no_show, cancelled_guest, cancelled_venue
        • datestring (date)krävs

          the service's date (a booking after midnight belongs to the evening before)

        • timestringkrävs
        • endstringkrävs
        • minutesintegerkrävs
        • partyintegerkrävs
        • starts_atstring (date-time)krävs

          with the venue's offset

        • ends_atstring (date-time)krävs
        • serviceobject | nullkrävs
          • idstringkrävs
          • nameText | nullkrävs
        • tablesarray of TableRefkrävs
          • idstringkrävs
          • codestringkrävs
        • seatingobjectkrävs

          the guest's seating choice {mode, zone?, tag?, table?}

        • sourcestringkrävs
          Värden: widget, site_link, qr, instagram, facebook, google, email, marketplace, api, phone, walk_in, staff, app, import
        • source_originstring | nullkrävs
        • utmobject | nullkrävs
          • sourcestring | nullkrävs
          • mediumstring | nullkrävs
          • campaignstring | nullkrävs
        • guestobject | nullkrävs
          • namestringkrävs
          • phonestring | nullkrävs
          • emailstring | nullkrävs
        • localestringkrävs
        • occasionstring | nullkrävs
          Värden: birthday, anniversary, date_night, business, celebration, other
        • accessibilityarray of stringkrävs
          Värden: wheelchair, step_free, walking_aid, hearing, vision, service_dog, high_chair, pram
        • requestsstring | nullkrävs
        • allergiesstring | nullkrävs
        • confirmed_atstring (date-time) | nullkrävs
        • late_minutesinteger | nullkrävs
        • cancelled_latebooleankrävs

          cancelled by the guest inside the cancellation window

        • status_atstring (date-time) | nullkrävs
        • created_atstring (date-time)krävs
        • updated_atstring (date-time)krävs
        • versionintegerkrävs

          grows with every change

  • 401No key, an unknown or a revoked key (unauthenticated).
    Huvuden: WWW-Authenticate
  • 402plan_required (feature, plan: the venue's company is on the Start plan) or subscription_inactive (status: its subscription is paused or canceled).
  • 403scope (the key lacks the scope in required) or company_suspended.
  • 409not_published: the venue's page is not published, so it takes no online bookings; payment_required: the hold's service takes a card guarantee, a deposit or a prepaid menu, which only TableFai's own booking pages take; preorder_required: the service needs a pre-order; or verification_required: the service asks a party of this size to verify with BankID (slice 8b), which only TableFai's own booking pages do.
  • 410hold_expired: the hold ran out, was released or is not the venue's.
  • 422validation with fields, or another refusal of the request (idempotency_mismatch, seating_unavailable, table_too_large).
  • 429rate_limited: more than 120 requests in a minute (retry_after in seconds).
    Huvuden: Retry-After

GET /bookings/{reference}

One booking (bookings:read)

Parametrar

Parametrar
NamnITypOm
referencekrävssökvägstring
localefrågastringthe language of the restaurant's textsVärden: en, sv

Svar

  • 200The booking.
    Huvuden: X-RateLimit-Limit, X-RateLimit-Remaining
    Svarets fält ({data: object})
    • dataobjectkrävs
      • bookingBookingkrävs

        A booking as the venue sees it, without its staff's own notes and tags.

        • referencestringkrävs
        • statusstringkrävs
          Värden: requested, confirmed, waitlisted, arrived, seated, finished, no_show, cancelled_guest, cancelled_venue
        • datestring (date)krävs

          the service's date (a booking after midnight belongs to the evening before)

        • timestringkrävs
        • endstringkrävs
        • minutesintegerkrävs
        • partyintegerkrävs
        • starts_atstring (date-time)krävs

          with the venue's offset

        • ends_atstring (date-time)krävs
        • serviceobject | nullkrävs
          • idstringkrävs
          • nameText | nullkrävs
        • tablesarray of TableRefkrävs
          • idstringkrävs
          • codestringkrävs
        • seatingobjectkrävs

          the guest's seating choice {mode, zone?, tag?, table?}

        • sourcestringkrävs
          Värden: widget, site_link, qr, instagram, facebook, google, email, marketplace, api, phone, walk_in, staff, app, import
        • source_originstring | nullkrävs
        • utmobject | nullkrävs
          • sourcestring | nullkrävs
          • mediumstring | nullkrävs
          • campaignstring | nullkrävs
        • guestobject | nullkrävs
          • namestringkrävs
          • phonestring | nullkrävs
          • emailstring | nullkrävs
        • localestringkrävs
        • occasionstring | nullkrävs
          Värden: birthday, anniversary, date_night, business, celebration, other
        • accessibilityarray of stringkrävs
          Värden: wheelchair, step_free, walking_aid, hearing, vision, service_dog, high_chair, pram
        • requestsstring | nullkrävs
        • allergiesstring | nullkrävs
        • confirmed_atstring (date-time) | nullkrävs
        • late_minutesinteger | nullkrävs
        • cancelled_latebooleankrävs

          cancelled by the guest inside the cancellation window

        • status_atstring (date-time) | nullkrävs
        • created_atstring (date-time)krävs
        • updated_atstring (date-time)krävs
        • versionintegerkrävs

          grows with every change

  • 401No key, an unknown or a revoked key (unauthenticated).
    Huvuden: WWW-Authenticate
  • 402plan_required (feature, plan: the venue's company is on the Start plan) or subscription_inactive (status: its subscription is paused or canceled).
  • 403scope (the key lacks the scope in required) or company_suspended.
  • 404not_found: not the key's venue's.
  • 429rate_limited: more than 120 requests in a minute (retry_after in seconds).
    Huvuden: Retry-After

POST /bookings/{reference}/cancel

Cancel for the venue (bookings:write)

cancelled_venue, from requested or confirmed; a cancelled booking answers as it is. The guest is told by mail. With version, only at that version (409 stale).

Parametrar

Parametrar
NamnITypOm
referencekrävssökvägstring
localefrågastringthe language of the restaurant's textsVärden: en, sv

Kropp object

  • versioninteger (≥ 1)

Svar

  • 200The booking, cancelled.
    Huvuden: X-RateLimit-Limit, X-RateLimit-Remaining
    Svarets fält ({data: object})
    • dataobjectkrävs
      • bookingBookingkrävs

        A booking as the venue sees it, without its staff's own notes and tags.

        • referencestringkrävs
        • statusstringkrävs
          Värden: requested, confirmed, waitlisted, arrived, seated, finished, no_show, cancelled_guest, cancelled_venue
        • datestring (date)krävs

          the service's date (a booking after midnight belongs to the evening before)

        • timestringkrävs
        • endstringkrävs
        • minutesintegerkrävs
        • partyintegerkrävs
        • starts_atstring (date-time)krävs

          with the venue's offset

        • ends_atstring (date-time)krävs
        • serviceobject | nullkrävs
          • idstringkrävs
          • nameText | nullkrävs
        • tablesarray of TableRefkrävs
          • idstringkrävs
          • codestringkrävs
        • seatingobjectkrävs

          the guest's seating choice {mode, zone?, tag?, table?}

        • sourcestringkrävs
          Värden: widget, site_link, qr, instagram, facebook, google, email, marketplace, api, phone, walk_in, staff, app, import
        • source_originstring | nullkrävs
        • utmobject | nullkrävs
          • sourcestring | nullkrävs
          • mediumstring | nullkrävs
          • campaignstring | nullkrävs
        • guestobject | nullkrävs
          • namestringkrävs
          • phonestring | nullkrävs
          • emailstring | nullkrävs
        • localestringkrävs
        • occasionstring | nullkrävs
          Värden: birthday, anniversary, date_night, business, celebration, other
        • accessibilityarray of stringkrävs
          Värden: wheelchair, step_free, walking_aid, hearing, vision, service_dog, high_chair, pram
        • requestsstring | nullkrävs
        • allergiesstring | nullkrävs
        • confirmed_atstring (date-time) | nullkrävs
        • late_minutesinteger | nullkrävs
        • cancelled_latebooleankrävs

          cancelled by the guest inside the cancellation window

        • status_atstring (date-time) | nullkrävs
        • created_atstring (date-time)krävs
        • updated_atstring (date-time)krävs
        • versionintegerkrävs

          grows with every change

  • 401No key, an unknown or a revoked key (unauthenticated).
    Huvuden: WWW-Authenticate
  • 402plan_required (feature, plan: the venue's company is on the Start plan) or subscription_inactive (status: its subscription is paused or canceled).
  • 403scope (the key lacks the scope in required) or company_suspended.
  • 404not_found: not the key's venue's.
  • 409slot_taken (with alternatives: [{date, time}]), not_published, invalid_transition (with from, to), stale, payment_required: the service takes a card guarantee, a deposit or a prepaid menu, which only TableFai's own booking pages take (the guest books there), preorder_required (the service needs a pre-order) or verification_required (the service asks the party to verify with BankID, slice 8b).
  • 429rate_limited: more than 120 requests in a minute (retry_after in seconds).
    Huvuden: Retry-After

Document

GET /openapi.json

This document

Öppen: ingen nyckel behövs.

Svar

  • 200OpenAPI 3.1.

Webhooks

Lägg till en https-adress under Webbplats och länkar → Webhooks och välj dess händelser. TableFai skickar JSON dit med POST inom en minut efter varje ändring.

  • TableFai-Signature: t=<unix>, v1=<hex> — en HMAC-SHA256 av "<t>.<rå kropp>" med webhookens nyckel (whsec_…)
  • TableFai-Event — händelsen: booking.created, booking.updated, booking.cancelled eller ping
  • TableFai-Delivery — denna leverans id: en händelse kan komma mer än en gång, använd händelsens id
  • Svara 2xx inom 10 sekunder. Allt annat försöks igen efter 1 min, 5 min, 30 min, 2 h, 6 h och 24 h; en webhook som misslyckas i tre dagar stängs av. Omdirigeringar följs inte.

Kontrollera signaturen

Kontrollera den över den råa kroppen innan ni tolkar den, med nyckeln precis som den visades, och neka ett t som ligger mer än fem minuter bort.

PHP

function tablefai_signed(string $body, string $header, string $secret, int $tolerance = 300): bool
{
    $t = null;
    $signatures = [];
    foreach (explode(',', $header) as $part) {
        [$name, $value] = array_pad(explode('=', trim($part), 2), 2, '');
        if ($name === 't') {
            $t = (int) $value;
        } elseif ($name === 'v1') {
            $signatures[] = $value;
        }
    }
    if ($t === null || abs(time() - $t) > $tolerance) {
        return false;
    }
    $expected = hash_hmac('sha256', $t.'.'.$body, $secret);
    foreach ($signatures as $signature) {
        if (hash_equals($expected, $signature)) {
            return true;
        }
    }

    return false;
}

$ok = tablefai_signed(file_get_contents('php://input'), $_SERVER['HTTP_TABLEFAI_SIGNATURE'] ?? '', getenv('TABLEFAI_WEBHOOK_SECRET'));

Node.js

import { createHmac, timingSafeEqual } from 'node:crypto';

export function tablefaiSigned(rawBody, header, secret, toleranceSeconds = 300) {
  const parts = header.split(',').map((part) => part.trim().split('='));
  const t = Number(parts.find(([name]) => name === 't')?.[1]);
  if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
  const expected = Buffer.from(createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex'));
  return parts.filter(([name]) => name === 'v1').some(([, signature]) => {
    const given = Buffer.from(signature ?? '');
    return given.length === expected.length && timingSafeEqual(given, expected);
  });
}
// Express: app.post('/tablefai', express.raw({ type: 'application/json' }), (req, res) =>
//   tablefaiSigned(req.body.toString('utf8'), req.get('TableFai-Signature') ?? '', process.env.TABLEFAI_WEBHOOK_SECRET)
//     ? res.sendStatus(204) : res.sendStatus(400));

Händelserna

POST booking.created

A booking was made (by staff, a guest or a partner)

Kroppens fält (BookingEvent)
  • idstringkrävs

    the event's id: the same for every webhook it goes to

  • typestringkrävs
    Värden: booking.created, booking.updated, booking.cancelled
  • created_atstring (date-time)krävs
  • venueEventVenuekrävs
    • idstringkrävs
    • slugstringkrävs
    • namestringkrävs
  • dataobjectkrävs
    • bookingBookingkrävs

      A booking as the venue sees it, without its staff's own notes and tags.

      • referencestringkrävs
      • statusstringkrävs
        Värden: requested, confirmed, waitlisted, arrived, seated, finished, no_show, cancelled_guest, cancelled_venue
      • datestring (date)krävs

        the service's date (a booking after midnight belongs to the evening before)

      • timestringkrävs
      • endstringkrävs
      • minutesintegerkrävs
      • partyintegerkrävs
      • starts_atstring (date-time)krävs

        with the venue's offset

      • ends_atstring (date-time)krävs
      • serviceobject | nullkrävs
        • idstringkrävs
        • nameText | nullkrävs
      • tablesarray of TableRefkrävs
        • idstringkrävs
        • codestringkrävs
      • seatingobjectkrävs

        the guest's seating choice {mode, zone?, tag?, table?}

      • sourcestringkrävs
        Värden: widget, site_link, qr, instagram, facebook, google, email, marketplace, api, phone, walk_in, staff, app, import
      • source_originstring | nullkrävs
      • utmobject | nullkrävs
        • sourcestring | nullkrävs
        • mediumstring | nullkrävs
        • campaignstring | nullkrävs
      • guestobject | nullkrävs
        • namestringkrävs
        • phonestring | nullkrävs
        • emailstring | nullkrävs
      • localestringkrävs
      • occasionstring | nullkrävs
        Värden: birthday, anniversary, date_night, business, celebration, other
      • accessibilityarray of stringkrävs
        Värden: wheelchair, step_free, walking_aid, hearing, vision, service_dog, high_chair, pram
      • requestsstring | nullkrävs
      • allergiesstring | nullkrävs
      • confirmed_atstring (date-time) | nullkrävs
      • late_minutesinteger | nullkrävs
      • cancelled_latebooleankrävs

        cancelled by the guest inside the cancellation window

      • status_atstring (date-time) | nullkrävs
      • created_atstring (date-time)krävs
      • updated_atstring (date-time)krävs
      • versionintegerkrävs

        grows with every change

Svar

  • 2XXDelivered. Anything else, or no answer within 10 seconds, is tried again.

POST booking.updated

A booking changed (time, party, tables, status, the guest's running late …)

Kroppens fält (BookingEvent)
  • idstringkrävs

    the event's id: the same for every webhook it goes to

  • typestringkrävs
    Värden: booking.created, booking.updated, booking.cancelled
  • created_atstring (date-time)krävs
  • venueEventVenuekrävs
    • idstringkrävs
    • slugstringkrävs
    • namestringkrävs
  • dataobjectkrävs
    • bookingBookingkrävs

      A booking as the venue sees it, without its staff's own notes and tags.

      • referencestringkrävs
      • statusstringkrävs
        Värden: requested, confirmed, waitlisted, arrived, seated, finished, no_show, cancelled_guest, cancelled_venue
      • datestring (date)krävs

        the service's date (a booking after midnight belongs to the evening before)

      • timestringkrävs
      • endstringkrävs
      • minutesintegerkrävs
      • partyintegerkrävs
      • starts_atstring (date-time)krävs

        with the venue's offset

      • ends_atstring (date-time)krävs
      • serviceobject | nullkrävs
        • idstringkrävs
        • nameText | nullkrävs
      • tablesarray of TableRefkrävs
        • idstringkrävs
        • codestringkrävs
      • seatingobjectkrävs

        the guest's seating choice {mode, zone?, tag?, table?}

      • sourcestringkrävs
        Värden: widget, site_link, qr, instagram, facebook, google, email, marketplace, api, phone, walk_in, staff, app, import
      • source_originstring | nullkrävs
      • utmobject | nullkrävs
        • sourcestring | nullkrävs
        • mediumstring | nullkrävs
        • campaignstring | nullkrävs
      • guestobject | nullkrävs
        • namestringkrävs
        • phonestring | nullkrävs
        • emailstring | nullkrävs
      • localestringkrävs
      • occasionstring | nullkrävs
        Värden: birthday, anniversary, date_night, business, celebration, other
      • accessibilityarray of stringkrävs
        Värden: wheelchair, step_free, walking_aid, hearing, vision, service_dog, high_chair, pram
      • requestsstring | nullkrävs
      • allergiesstring | nullkrävs
      • confirmed_atstring (date-time) | nullkrävs
      • late_minutesinteger | nullkrävs
      • cancelled_latebooleankrävs

        cancelled by the guest inside the cancellation window

      • status_atstring (date-time) | nullkrävs
      • created_atstring (date-time)krävs
      • updated_atstring (date-time)krävs
      • versionintegerkrävs

        grows with every change

Svar

  • 2XXDelivered. Anything else, or no answer within 10 seconds, is tried again.

POST booking.cancelled

A booking was cancelled (by the guest or the venue)

Kroppens fält (BookingEvent)
  • idstringkrävs

    the event's id: the same for every webhook it goes to

  • typestringkrävs
    Värden: booking.created, booking.updated, booking.cancelled
  • created_atstring (date-time)krävs
  • venueEventVenuekrävs
    • idstringkrävs
    • slugstringkrävs
    • namestringkrävs
  • dataobjectkrävs
    • bookingBookingkrävs

      A booking as the venue sees it, without its staff's own notes and tags.

      • referencestringkrävs
      • statusstringkrävs
        Värden: requested, confirmed, waitlisted, arrived, seated, finished, no_show, cancelled_guest, cancelled_venue
      • datestring (date)krävs

        the service's date (a booking after midnight belongs to the evening before)

      • timestringkrävs
      • endstringkrävs
      • minutesintegerkrävs
      • partyintegerkrävs
      • starts_atstring (date-time)krävs

        with the venue's offset

      • ends_atstring (date-time)krävs
      • serviceobject | nullkrävs
        • idstringkrävs
        • nameText | nullkrävs
      • tablesarray of TableRefkrävs
        • idstringkrävs
        • codestringkrävs
      • seatingobjectkrävs

        the guest's seating choice {mode, zone?, tag?, table?}

      • sourcestringkrävs
        Värden: widget, site_link, qr, instagram, facebook, google, email, marketplace, api, phone, walk_in, staff, app, import
      • source_originstring | nullkrävs
      • utmobject | nullkrävs
        • sourcestring | nullkrävs
        • mediumstring | nullkrävs
        • campaignstring | nullkrävs
      • guestobject | nullkrävs
        • namestringkrävs
        • phonestring | nullkrävs
        • emailstring | nullkrävs
      • localestringkrävs
      • occasionstring | nullkrävs
        Värden: birthday, anniversary, date_night, business, celebration, other
      • accessibilityarray of stringkrävs
        Värden: wheelchair, step_free, walking_aid, hearing, vision, service_dog, high_chair, pram
      • requestsstring | nullkrävs
      • allergiesstring | nullkrävs
      • confirmed_atstring (date-time) | nullkrävs
      • late_minutesinteger | nullkrävs
      • cancelled_latebooleankrävs

        cancelled by the guest inside the cancellation window

      • status_atstring (date-time) | nullkrävs
      • created_atstring (date-time)krävs
      • updated_atstring (date-time)krävs
      • versionintegerkrävs

        grows with every change

Svar

  • 2XXDelivered. Anything else, or no answer within 10 seconds, is tried again.

POST ping

A test from the venue's settings

Kroppens fält (PingEvent)
  • idstringkrävs
  • type"ping"krävs
  • created_atstring (date-time)krävs
  • venueEventVenuekrävs
    • idstringkrävs
    • slugstringkrävs
    • namestringkrävs
  • dataobjectkrävs
    • webhookstringkrävs

Svar

  • 2XXDelivered. Anything else, or no answer within 10 seconds, is tried again.