API referenceTenvelo API
https://api.tenvelo.com The contract, as OpenAPI

Contract 2026-10-10. Every path below carries its own major version.

Online ordering · Reference

Online ordering

The guest-facing ordering site's own surface: a location's public catalog, read without a token, and the session a table's QR code opens. The orders it produces are written through orders/batch-upsert, to the same ledger a till writes to.

Operations
40
Base
https://api.tenvelo.com
  1. POST/v1/channel-commissions

    Record a channel's cost at a location

    No. createChannelCommissionAuth ordering:write

    A channel's stated cost, in force from a business date. A change is a new version, so the net of orders already taken is not restated; the same channel and date again corrects that version. The rate is the merchant's estimate of what a channel takes, a cost against revenue and never a tender. An owner or a manager.

    Parameters

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Request body application/json · ChannelCommissionCreate

    • channelstring · enum

      Required

      onlineintegration

    • effective_fromstring · date

      Required

    • location_idstring · uuid

      Required

    • percentagePercentage

      Required

      A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

      A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

      pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

    Responses

    • 201

      The version, recorded.

      ChannelCommission · application/json
      • channelstring · enum

        Required

        onlineintegration

      • effective_fromstring · date

        RequiredNullable

        The business date it first applies, or null for a rate in force since the start.

      • percentagePercentage

        Required

        A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

        A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

        pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

      • statestring · enum

        Required

        Where the version stands on the location's business date today.

        in_forcescheduledsuperseded

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

  2. GET/v1/locations/lookup

    Find a location by its ordering page's handle

    No. getOrderingLocationAuth no token

    The location whose ordering page is {handle}.tenvelo.app, as its guests see it, with the id every other operation of the location takes. Public: the guest site knows its handle from the host it was loaded on and nothing else (docs/decisions/0113). A handle no location holds, or one whose page is off, is a 404.

    Parameters

    • ordering_handlequery · string

      Required

      The ordering page's handle, its subdomain on the guest site.

    Responses

    • 200

      The location.

      OnlineLocation · application/json
      • idstring · uuid

        Required

        The location's id, which every operation at the location takes.

      • namestring

        Required

      • addressAddress

        A postal address.

        The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

        The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

        • address_line_1string

          Required

          First line of the address — street number, street name, building name.

          ≤ 255 chars

        • address_line_2string

          Second line of the address, if any.

          ≤ 255 chars

        • address_line_3string

          Third line of the address, if any.

          ≤ 255 chars

        • administrative_district_level_1string

          A civil entity within the country. The state in the US; the county in the UK.

          ≤ 128 chars

        • administrative_district_level_2string

          A civil entity within administrative_district_level_1.

          ≤ 128 chars

        • countryCountry

          Required

          ISO 3166-1 alpha-2 country code.

          ZZ is the unknown/unspecified placeholder.

          One of 250 values; see the schema.

        • localitystring

          The city or town.

          ≤ 128 chars

        • postal_codestring

          The postal or ZIP code.

          ≤ 32 chars

        • sublocalitystring

          A civil region within the locality, if any.

          ≤ 128 chars

      • business_namestring

        Required

        The business the location belongs to.

      • currencystring

        Required

        The currency every price here is in (ISO 4217).

      • orderingOrdering

        Required

        Whether the location takes orders now, and how soon one is ready.

        • deliversboolean

          Whether the venue delivers orders from its own page, so the checkout offers a delivery address beside collection.

        • openboolean

          Required

          False while the location has paused ordering.

        • prep_time_minutesinteger

          About how long an order takes to be ready. Absent when the location does not say.

          ≥ 1

      • phone_numberstring
      • timezonestring

        Required

        The location's IANA time zone, which its clock times are told in.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  3. POST/v1/locations/{id}/book

    Book a table

    No. createLocationBookingAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    Books a table for a guest at one of the times offered. The time is checked again here, so one taken since the guest looked is refused with a 422 on starts_at. The guest is emailed a confirmation with the links to change or cancel it.

    The app mints the id when the guest starts booking, so a retry after a lost answer is the booking it already made. Rate limited per client address.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Request body application/json · BookingCreate

    • idstring · uuid

      Required

      Minted by the app when the guest starts booking, so a retry is the same booking.

    • namestring

      Required

      1–200 chars

    • emailstring

      Required

      Where the confirmation goes, with the links to change or cancel.

      3–320 chars

    • notestring

      Anything the location should know.

      ≤ 1000 chars

    • party_sizeinteger · int32

      Required

      1–100

    • phonestring

      Only if the guest would like a reminder by text.

      ≤ 40 chars

    • starts_atstring · date-time

      Required

      One of the offered times.

    Responses

    • 201

      The table is booked.

      BookingConfirmation · application/json
      • idstring · uuid

        Required

      • emailstring

        Required

        Where the confirmation was sent.

      • party_sizeinteger

        Required

      • starts_atstring · date-time

        Required

      • tokenstring

        The booking's link token, which the email's change-or-cancel link carries. The guest who made the booking holds it, and may use it to change or cancel the booking — or add a deposit to it — without signing in. Only its hash is kept.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 409

      The request conflicts with current state — a uniqueness constraint, or an attempt to mutate an order that is already completed or voided.

      Unlike 412, re-reading and retrying unchanged will not resolve it; the request itself has to change.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 415

      The request Content-Type is not supported. This API accepts application/json on all mutations.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  4. GET/v1/locations/{id}/booking-times

    Get the times a party can book

    No. getLocationBookingTimesAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    What a guest booking a table needs: the location, how far ahead and how large a party it takes online, and, given a date and a party_size, the times the room can take them that day. A location that takes no bookings online answers without online_booking and with no times. Rate limited per client address, since each answer reads the location's diary.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • datequery · string · date

      The day, on the location's own calendar.

    • party_sizequery · integer

    Responses

    • 200

      The location's booking terms, and the times on the day asked about.

      BookingTimes · application/json
      • locationOrderLocation

        Required

        The location an order is collected from.

        • namestring

          Required

        • addressAddress

          A postal address.

          The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

          The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

          • address_line_1string

            Required

            First line of the address — street number, street name, building name.

            ≤ 255 chars

          • address_line_2string

            Second line of the address, if any.

            ≤ 255 chars

          • address_line_3string

            Third line of the address, if any.

            ≤ 255 chars

          • administrative_district_level_1string

            A civil entity within the country. The state in the US; the county in the UK.

            ≤ 128 chars

          • administrative_district_level_2string

            A civil entity within administrative_district_level_1.

            ≤ 128 chars

          • countryCountry

            Required

            ISO 3166-1 alpha-2 country code.

            ZZ is the unknown/unspecified placeholder.

            One of 250 values; see the schema.

          • localitystring

            The city or town.

            ≤ 128 chars

          • postal_codestring

            The postal or ZIP code.

            ≤ 32 chars

          • sublocalitystring

            A civil region within the locality, if any.

            ≤ 128 chars

        • business_namestring

          Required

        • currencyCurrency

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

        • phone_numberstring
        • timezonestring

          Required

          The location's IANA time zone, which its clock times are told in.

      • online_bookingOnlineBookingTerms

        How the location takes bookings online, as a guest sees it. Absent when it takes none.

        • days_aheadinteger

          Required

          How many days after today a guest may book. Zero is today only.

          ≥ 0

        • deposit_per_personMoney

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • max_party_sizeinteger

          Required

          The largest party a guest may book online. A larger one is a call to the location.

          ≥ 1

        • waitlist_enabledboolean

          Whether guests may join this location's waitlist from its page. Absent means no.

      • timesarray of BookingTime

        Required

        The times the room can take the party, earliest first. Empty until a date and a party_size are given.

        • service_periodstring

          The name of the service running then, such as lunch or dinner. Absent when the location names none.

        • starts_atstring · date-time

          Required

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  5. GET/v1/locations/{id}/bookings/{booking_id}

    Get a booking by its link

    No. getLocationBookingAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    A booking as the guest who made it sees it, from the link in its confirmation. The link is the credential, so a wrong token is a 404, and so is a booking at another location. Rate limited per client address.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • booking_idpath · string · uuid

      Required

      The booking, by its id.

    • tokenquery · string

      Required

      The token the guest's link carries, as the email or receipt gave it. It is the credential.

    Responses

    • 200

      The booking.

      HeldBooking · application/json
      • idstring · uuid

        Required

      • namestring

        Required

        Who the table is booked for.

      • locationOrderLocation

        Required

        The location an order is collected from.

        • namestring

          Required

        • addressAddress

          A postal address.

          The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

          The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

          • address_line_1string

            Required

            First line of the address — street number, street name, building name.

            ≤ 255 chars

          • address_line_2string

            Second line of the address, if any.

            ≤ 255 chars

          • address_line_3string

            Third line of the address, if any.

            ≤ 255 chars

          • administrative_district_level_1string

            A civil entity within the country. The state in the US; the county in the UK.

            ≤ 128 chars

          • administrative_district_level_2string

            A civil entity within administrative_district_level_1.

            ≤ 128 chars

          • countryCountry

            Required

            ISO 3166-1 alpha-2 country code.

            ZZ is the unknown/unspecified placeholder.

            One of 250 values; see the schema.

          • localitystring

            The city or town.

            ≤ 128 chars

          • postal_codestring

            The postal or ZIP code.

            ≤ 32 chars

          • sublocalitystring

            A civil region within the locality, if any.

            ≤ 128 chars

        • business_namestring

          Required

        • currencyCurrency

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

        • phone_numberstring
        • timezonestring

          Required

          The location's IANA time zone, which its clock times are told in.

      • party_sizeinteger

        Required

        ≥ 1

      • starts_atstring · date-time

        Required

      • statusstring · enum

        Required

        Only a confirmed booking can be moved or canceled.

        confirmedseatedfinishedcanceledno_show

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  6. POST/v1/locations/{id}/bookings/{booking_id}/cancel

    Cancel a booking by its link

    No. cancelLocationBookingAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    Cancels a booking from the link in its confirmation. Opening the link never cancels: a mail scanner follows links nobody clicked, so the app asks first and cancelling is this call. Canceling one already canceled answers it as it is. Rate limited per client address.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • booking_idpath · string · uuid

      Required

      The booking, by its id.

    • tokenquery · string

      Required

      The token the guest's link carries, as the email or receipt gave it. It is the credential.

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Responses

    • 200

      The booking, canceled.

      HeldBooking · application/json
      • idstring · uuid

        Required

      • namestring

        Required

        Who the table is booked for.

      • locationOrderLocation

        Required

        The location an order is collected from.

        • namestring

          Required

        • addressAddress

          A postal address.

          The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

          The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

          • address_line_1string

            Required

            First line of the address — street number, street name, building name.

            ≤ 255 chars

          • address_line_2string

            Second line of the address, if any.

            ≤ 255 chars

          • address_line_3string

            Third line of the address, if any.

            ≤ 255 chars

          • administrative_district_level_1string

            A civil entity within the country. The state in the US; the county in the UK.

            ≤ 128 chars

          • administrative_district_level_2string

            A civil entity within administrative_district_level_1.

            ≤ 128 chars

          • countryCountry

            Required

            ISO 3166-1 alpha-2 country code.

            ZZ is the unknown/unspecified placeholder.

            One of 250 values; see the schema.

          • localitystring

            The city or town.

            ≤ 128 chars

          • postal_codestring

            The postal or ZIP code.

            ≤ 32 chars

          • sublocalitystring

            A civil region within the locality, if any.

            ≤ 128 chars

        • business_namestring

          Required

        • currencyCurrency

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

        • phone_numberstring
        • timezonestring

          Required

          The location's IANA time zone, which its clock times are told in.

      • party_sizeinteger

        Required

        ≥ 1

      • starts_atstring · date-time

        Required

      • statusstring · enum

        Required

        Only a confirmed booking can be moved or canceled.

        confirmedseatedfinishedcanceledno_show

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 409

      The request conflicts with current state — a uniqueness constraint, or an attempt to mutate an order that is already completed or voided.

      Unlike 412, re-reading and retrying unchanged will not resolve it; the request itself has to change.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  7. POST/v1/locations/{id}/bookings/{booking_id}/deposit

    Hold the booking with a card

    No. depositLocationBookingAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    Holds a card-not-present authorisation against a booking the guest made itself (its link token proves it), for the venue's own per-person online deposit on the booking's party size. The card is the processor's token minted by its own card field, never a number; one deposit per booking, under an id derived from the booking, so a retry asks that same authorisation again rather than taking a second one. The venue must offer a deposit online, and the booking must still be confirmed — one already canceled, seated or refunded cannot be held.

    What releases or captures it is the party's visit: seating or cancelling releases the hold, marking a no-show captures it as the fee. Rate limited per client address.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • booking_idpath · string · uuid

      Required

      The booking to hold, by its id.

    • tokenquery · string

      Required

      The token the guest's link carries, as the email or receipt gave it. It is the credential.

    Request body application/json · BookingCustomerDepositRequest

    • cardstring

      Required

      The processor's token for the card, never a card number.

      1–256 chars

    Responses

    • 200

      The deposit, as it stands immediately after the ask.

      BookingDeposit · application/json
      • amountMoney

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • card_brandstring

        The card's scheme, as the processor reported it.

      • card_last4string

        The last four digits of the card, as the processor reported them.

      • statusstring · enum

        pending — the ask was recorded, the processor has not answered.

        held — the amount is authorised, not taken.

        declined — the processor refused the authorisation.

        unknown — contact was lost; only the processor knows.

        released — the hold was lifted; nothing was taken.

        captured — the fee was taken on a no-show.

        capture_declined — the party did not come and the card did not pay.

        release_failed — the processor refused the release.

        pendinghelddeclinedunknownreleasedcapturedcapture_declinedrelease_failed

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 409

      The request conflicts with current state — a uniqueness constraint, or an attempt to mutate an order that is already completed or voided.

      Unlike 412, re-reading and retrying unchanged will not resolve it; the request itself has to change.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 415

      The request Content-Type is not supported. This API accepts application/json on all mutations.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  8. POST/v1/locations/{id}/bookings/{booking_id}/reschedule

    Move a booking by its link

    No. rescheduleLocationBookingAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    Moves a booking to another time or party size, from the link in its confirmation. The time is one GET /v1/locations/{id}/booking-times offers for the size asked, checked again here, so one taken since the guest looked is a 422 on starts_at. A booking that has been canceled or seated can't be moved (409). The guest is emailed the new confirmation. Rate limited per client address.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • booking_idpath · string · uuid

      Required

      The booking, by its id.

    • tokenquery · string

      Required

      The token the guest's link carries, as the email or receipt gave it. It is the credential.

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Request body application/json · BookingReschedule

    • party_sizeinteger

      Required

      1–100

    • starts_atstring · date-time

      Required

      One of the times GET /v1/locations/{id}/booking-times offers for this party size.

    Responses

    • 200

      The booking, moved.

      HeldBooking · application/json
      • idstring · uuid

        Required

      • namestring

        Required

        Who the table is booked for.

      • locationOrderLocation

        Required

        The location an order is collected from.

        • namestring

          Required

        • addressAddress

          A postal address.

          The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

          The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

          • address_line_1string

            Required

            First line of the address — street number, street name, building name.

            ≤ 255 chars

          • address_line_2string

            Second line of the address, if any.

            ≤ 255 chars

          • address_line_3string

            Third line of the address, if any.

            ≤ 255 chars

          • administrative_district_level_1string

            A civil entity within the country. The state in the US; the county in the UK.

            ≤ 128 chars

          • administrative_district_level_2string

            A civil entity within administrative_district_level_1.

            ≤ 128 chars

          • countryCountry

            Required

            ISO 3166-1 alpha-2 country code.

            ZZ is the unknown/unspecified placeholder.

            One of 250 values; see the schema.

          • localitystring

            The city or town.

            ≤ 128 chars

          • postal_codestring

            The postal or ZIP code.

            ≤ 32 chars

          • sublocalitystring

            A civil region within the locality, if any.

            ≤ 128 chars

        • business_namestring

          Required

        • currencyCurrency

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

        • phone_numberstring
        • timezonestring

          Required

          The location's IANA time zone, which its clock times are told in.

      • party_sizeinteger

        Required

        ≥ 1

      • starts_atstring · date-time

        Required

      • statusstring · enum

        Required

        Only a confirmed booking can be moved or canceled.

        confirmedseatedfinishedcanceledno_show

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 409

      The request conflicts with current state — a uniqueness constraint, or an attempt to mutate an order that is already completed or voided.

      Unlike 412, re-reading and retrying unchanged will not resolve it; the request itself has to change.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 415

      The request Content-Type is not supported. This API accepts application/json on all mutations.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  9. GET/v1/locations/{id}/catalog

    Get the location's catalog

    No. getLocationCatalogAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    Everything the location sells online, by category in the order the location sets, each product with the price a guest starts from and whether it has choices to make. It is the same for every guest of the location, so it is cacheable: Cache-Control: public, with an ETag to revalidate against.

    A location that has paused ordering still answers, with ordering.open false, so a guest can see what they would have ordered and come back.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • If-None-Matchheader · string

      The ETag of a copy the caller holds. If it is still current, the answer is 304 with no body (RFC 9110 §13.1.2).

    Responses

    • 200

      The location's catalog.

      OnlineCatalog · application/json
      • categoriesarray of OnlineCatalogCategory

        Required

        The categories with something in them, in the location's order. Products in no category, or in one no longer listed, come last in a category with no id.

        • idstring · uuid

          Absent for the products in no category.

        • namestring

          Absent for the products in no category.

        • productsarray of OnlineProductSummary

          Required

          • idstring · uuid

            Required

          • namestring

            Required

          • allergensarray of string

            Required

          • availableboolean

            Required

            False while it is sold out, or outside the hours it is sold.

          • descriptionstring
          • has_choicesboolean

            Required

            Whether a guest has a variant or modifiers to choose before adding it.

          • image_urlstring · uri
          • priceMoney

            Required

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

          • several_pricesboolean

            Required

            Whether its variants are priced differently, so price is where it starts.

      • locationOnlineLocation

        Required

        The location a guest is ordering from.

        • idstring · uuid

          Required

          The location's id, which every operation at the location takes.

        • namestring

          Required

        • addressAddress

          A postal address.

          The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

          The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

          • address_line_1string

            Required

            First line of the address — street number, street name, building name.

            ≤ 255 chars

          • address_line_2string

            Second line of the address, if any.

            ≤ 255 chars

          • address_line_3string

            Third line of the address, if any.

            ≤ 255 chars

          • administrative_district_level_1string

            A civil entity within the country. The state in the US; the county in the UK.

            ≤ 128 chars

          • administrative_district_level_2string

            A civil entity within administrative_district_level_1.

            ≤ 128 chars

          • countryCountry

            Required

            ISO 3166-1 alpha-2 country code.

            ZZ is the unknown/unspecified placeholder.

            One of 250 values; see the schema.

          • localitystring

            The city or town.

            ≤ 128 chars

          • postal_codestring

            The postal or ZIP code.

            ≤ 32 chars

          • sublocalitystring

            A civil region within the locality, if any.

            ≤ 128 chars

        • business_namestring

          Required

          The business the location belongs to.

        • currencystring

          Required

          The currency every price here is in (ISO 4217).

        • orderingOrdering

          Required

          Whether the location takes orders now, and how soon one is ready.

          • deliversboolean

            Whether the venue delivers orders from its own page, so the checkout offers a delivery address beside collection.

          • openboolean

            Required

            False while the location has paused ordering.

          • prep_time_minutesinteger

            About how long an order takes to be ready. Absent when the location does not say.

            ≥ 1

        • phone_numberstring
        • timezonestring

          Required

          The location's IANA time zone, which its clock times are told in.

    • 304

      The copy the caller holds is current (RFC 9110 §15.4.5).

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  10. GET/v1/locations/{id}/customer-loyalty/{token}

    Get a guest's loyalty statement by a receipt's link

    No. getLocationCustomerLoyaltyStatementAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    A guest's points: the balance and what it is worth here, their tier and the distance to the next, the rewards the programme offers, and the recent movements. The link is the credential, so a wrong one is a 404, and so is a guest of another business than the location's. Rate limited per client address.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • tokenpath · string

      Required

      The token a receipt's loyalty link carries. It is the credential.

    Responses

    • 200

      The guest's statement.

      LoyaltyStatement · application/json
      • balanceinteger · int64

        Required

        Points held.

      • business_namestring

        Required

      • customer_namestring

        Required

        The guest's name as the business records it.

      • entriesarray of CustomerPointsEntry

        Required

        The recent movements, newest first.

        • typestring · enum

          Required

          Why the points moved. A demote carries no points; it records the guest falling a tier.

          earnredeemexpirereverseadjustdemote

        • created_atstring · date-time

          Required

        • location_namestring

          Where the sale behind it was rung. Absent for a movement with no sale.

        • pointsinteger · int64

          Required

          The change, signed.

        • reward_namestring

          The reward the points were spent on, for a redeem.

      • expiryCustomerPointsExpiry

        Required

        How the guest's points can lapse, so the page says so before they do. Zero means that rule is off.

        • inactivity_daysinteger

          Required

          The whole balance lapses after this many days without earning.

          ≥ 0

        • per_earn_daysinteger

          Required

          Points lapse this many days after they were earned.

          ≥ 0

      • rewardsarray of LoyaltyRewardOffer

        Required

        What the programme offers, cheapest first.

        • namestring

          Required

        • affordableboolean

          Required

          Whether the balance covers it now.

        • cost_pointsinteger · int64

          Required

      • tierLoyaltyTierStanding

        Where the guest stands in the programme's tiers. Absent when it has none.

        • currentstring

          The tier the guest is on. Absent below the lowest.

        • nextstring

          The tier above. Absent at the top.

        • spend_neededMoney

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • visits_neededinteger · int64

          How many more visits reach next, when the next tier is reached by visiting.

      • worthMoney

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  11. GET/v1/locations/{id}/gift-cards/{code}

    Get a gift card's balance by its link

    No. getLocationGiftCardBalanceAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    What is left on a gift card, for whoever holds the link it was emailed or printed with. The code and the token together are the credential, so a wrong token is a 404, and so is a card of another business than the location's. Rate limited per client address.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • codepath · string

      Required

      The card's code, as its balance link carries it. It spends the card at a till, so it is never logged.

    • tokenquery · string

      Required

      The token the guest's link carries, as the email or receipt gave it. It is the credential.

    Responses

    • 200

      The card's balance.

      GiftCardBalance · application/json
      • balanceMoney

        Required

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • business_namestring

        Required

        The business the card is spent at.

      • codestring

        Required

      • expires_atstring · date-time

        When the card stops being accepted. Absent for a card that never expires.

      • statusstring · enum

        Required

        Only an active card can be spent. One with nothing left is empty; one the business has voided is inactive.

        activeinactiveempty

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  12. POST/v1/locations/{id}/order

    Place an order

    No. createLocationOrderAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    Places a guest's order for collection. The app mints the order's id and the status_token its link is made of when the guest opens checkout, so pressing twice, or a retry after a lost answer, places one order and lands on the same link. The basket is priced again here; a line that can no longer be ordered refuses the whole order with a 422 naming it.

    Paid at the counter on collection. Rate limited per client address, so a script cannot fill a kitchen's queue with orders nobody will collect.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Request body application/json · OrderCreate

    • idstring · uuid

      Required

      The order's id, minted by the app when checkout opened.

    • customer_emailstring

      Required

      Where the confirmation and the order's progress are sent.

    • customer_namestring

      Required

      The name the counter calls out.

    • customer_phonestring

      In case the location needs to reach the guest.

    • delivery_addressAddress

      A postal address.

      The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

      The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

      • address_line_1string

        Required

        First line of the address — street number, street name, building name.

        ≤ 255 chars

      • address_line_2string

        Second line of the address, if any.

        ≤ 255 chars

      • address_line_3string

        Third line of the address, if any.

        ≤ 255 chars

      • administrative_district_level_1string

        A civil entity within the country. The state in the US; the county in the UK.

        ≤ 128 chars

      • administrative_district_level_2string

        A civil entity within administrative_district_level_1.

        ≤ 128 chars

      • countryCountry

        Required

        ISO 3166-1 alpha-2 country code.

        ZZ is the unknown/unspecified placeholder.

        One of 250 values; see the schema.

      • localitystring

        The city or town.

        ≤ 128 chars

      • postal_codestring

        The postal or ZIP code.

        ≤ 32 chars

      • sublocalitystring

        A civil region within the locality, if any.

        ≤ 128 chars

    • fulfillment_typestring · enum

      How the order leaves the building. Absent is collection, and the page offers delivery only when the venue delivers. A delivery order carries delivery_address.

      pickupdelivery

    • linesarray of BasketLine

      Required

      ≥ 1 items · ≤ 50 items

      • modifier_idsarray of string · uuid

        ≤ 50 items

      • notestring

        ≤ 200 chars

      • product_idstring · uuid

        Required

      • quantityQuantity

        Required

        How much of something, as a decimal string in the unit_of_measure beside it (each where there is none), as Square's quantity is: three croissants are "3", 1.4 kg of beans is "1.4". A string because a JSON number is a binary float to most parsers.

        It has at most as many decimal places as its unit's base unit holds — three in each, g and ml, six in kg and l — and a finer one is refused, never rounded. Tenvelo holds every quantity as an integer of that base unit (thousandths of an each, milligrams, microlitres; docs/decisions/0063); a client that computes with one should read the digits the same way, never through a float.

        ≤ 26 chars · pattern ^-?(0|[1-9][0-9]*)(\.[0-9]{1,6})?$

      • variant_idstring · uuid
    • marketing_consentboolean

      Required

      Whether the guest ticked to hear from the business. An order is never a yes on its own.

    • pickup_atstring · date-time

      The collection time chosen. Absent for as soon as it can be ready.

    • status_tokenstring

      Required

      The order's link, 32 random bytes as unpadded base64url, minted by the app when checkout opened.

      43–43 chars

    Responses

    • 201

      The order is placed, and its link works.

      PlacedOrder · application/json
      • idstring · uuid

        Required

      • status_tokenstring

        Required

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 415

      The request Content-Type is not supported. This API accepts application/json on all mutations.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 428

      The bearer is a guest account that has not agreed to share its details with this merchant yet (docs/decisions/0115 §6). The body is a problem document whose url names the issuer's share page for the moment the API minted; the app opens it, the guest answers, and the same order is retried (0117 §2).

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  13. GET/v1/locations/{id}/ordering-settings

    Get a location's online ordering settings

    No. getOrderingSettingsAuth ordering:write

    How the location's ordering page and its tables take orders, and each channel's stated cost with the versions behind it. Any person at the location reads it.

    Parameters

    • idpath · string · uuid

      Required

      UUIDv7 of the resource.

      For resources a device can originate — orders, and their line items — this id is minted by the client before the record is ever synced, which is what makes an offline create idempotent.

    Responses

    • 200

      The settings.

      OrderingSettings · application/json
      • auto_acceptboolean

        Required

        Whether an order from the page is accepted as it arrives, rather than waiting for somebody to take it on.

      • channel_commissionsarray of ChannelCommission

        Required

        Every version of each channel's stated cost, newest first per channel, as it stands on the location's business date.

        • channelstring · enum

          Required

          onlineintegration

        • effective_fromstring · date

          RequiredNullable

          The business date it first applies, or null for a rate in force since the start.

        • percentagePercentage

          Required

          A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

          A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

          pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

        • statestring · enum

          Required

          Where the version stands on the location's business date today.

          in_forcescheduledsuperseded

      • customer_opens_orderboolean

        Required

        Whether a customer's first round at an empty table opens its order, with no server on it until one picks it up. Means nothing with order_and_pay off.

      • days_aheadinteger · int32

        How many days beyond today a guest may choose a pickup time; zero keeps the page's same-day window (online-ordering item 15).

        0–14

      • delivery_enabledboolean

        Required

        Whether the venue delivers orders from its own page — the checkout then offers the guest a delivery address beside collection, and a delivery order carries it. Off, the page is collection only.

      • delivery_feeMoney

        Required

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • enabledboolean

        Required

        Whether guests can order from the location's ordering page.

      • handlestring

        Required

        The ordering page's name, its subdomain on the guest ordering site; empty until one is chosen.

        ≤ 63 chars

      • location_idstring · uuid

        Required

      • marketplace_listedboolean

        Required

        Whether the location is listed on the marketplace, tenvelo.app and the Tenvelo app. Joining needs an address, coordinates, business hours and a way to order.

      • order_and_payboolean

        Required

        Whether a guest scanning a table's code sees the bill and can ask to pay.

      • page_urlstring · uri

        RequiredNullable

        Where guests find the ordering page, or null with no handle.

      • pausedboolean

        Required

        Whether new orders are being refused for now. Its own switch, /pause and /resume.

      • prep_time_minutesinteger · int32

        Required

        What the page quotes for collection, in minutes.

        ≥ 0

      • versioninteger · int64

        Required

        The location's version, which a change is made over (If-Match).

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

  14. PATCH/v1/locations/{id}/ordering-settings

    Change a location's online ordering settings

    No. updateOrderingSettingsAuth ordering:write

    Applies a JSON Merge Patch (RFC 7396) to the settings, guarded by If-Match on the version read, which is the location's. The pause is its own switch (/pause, /resume), and a channel's cost is recorded by version (/v1/channel-commissions). An owner or a manager.

    Parameters

    • idpath · string · uuid

      Required

      UUIDv7 of the resource.

      For resources a device can originate — orders, and their line items — this id is minted by the client before the record is ever synced, which is what makes an offline create idempotent.

    • If-Matchheader · string

      Required

      The ETag from the read that produced the value you are updating.

      Required on updates, not optional, because "last write wins" is the wrong default for a catalogue two managers might edit at once. If anything has been written since your read, the request is rejected with 412 and you re-read and re-apply.

      Use * to mean "write regardless of current version" — an explicit, greppable override rather than the silent default.

    Request body application/merge-patch+json · OrderingSettingsPatch

    • auto_acceptboolean
    • customer_opens_orderboolean
    • days_aheadinteger · int32

      0–14

    • delivery_enabledboolean
    • delivery_feeMoney

      A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

      The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

      Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

      • amountinteger · int64

        Required

        The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

      • currencyCurrency

        Required

        ISO 4217 currency code.

        Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

        One of 182 values; see the schema.

    • enabledboolean
    • handlestring

      ≤ 63 chars

    • marketplace_listedboolean
    • order_and_payboolean
    • prep_time_minutesinteger · int32

      ≥ 0

    Responses

    • 200

      The settings as saved.

      OrderingSettings · application/json
      • auto_acceptboolean

        Required

        Whether an order from the page is accepted as it arrives, rather than waiting for somebody to take it on.

      • channel_commissionsarray of ChannelCommission

        Required

        Every version of each channel's stated cost, newest first per channel, as it stands on the location's business date.

        • channelstring · enum

          Required

          onlineintegration

        • effective_fromstring · date

          RequiredNullable

          The business date it first applies, or null for a rate in force since the start.

        • percentagePercentage

          Required

          A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

          A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

          pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

        • statestring · enum

          Required

          Where the version stands on the location's business date today.

          in_forcescheduledsuperseded

      • customer_opens_orderboolean

        Required

        Whether a customer's first round at an empty table opens its order, with no server on it until one picks it up. Means nothing with order_and_pay off.

      • days_aheadinteger · int32

        How many days beyond today a guest may choose a pickup time; zero keeps the page's same-day window (online-ordering item 15).

        0–14

      • delivery_enabledboolean

        Required

        Whether the venue delivers orders from its own page — the checkout then offers the guest a delivery address beside collection, and a delivery order carries it. Off, the page is collection only.

      • delivery_feeMoney

        Required

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • enabledboolean

        Required

        Whether guests can order from the location's ordering page.

      • handlestring

        Required

        The ordering page's name, its subdomain on the guest ordering site; empty until one is chosen.

        ≤ 63 chars

      • location_idstring · uuid

        Required

      • marketplace_listedboolean

        Required

        Whether the location is listed on the marketplace, tenvelo.app and the Tenvelo app. Joining needs an address, coordinates, business hours and a way to order.

      • order_and_payboolean

        Required

        Whether a guest scanning a table's code sees the bill and can ask to pay.

      • page_urlstring · uri

        RequiredNullable

        Where guests find the ordering page, or null with no handle.

      • pausedboolean

        Required

        Whether new orders are being refused for now. Its own switch, /pause and /resume.

      • prep_time_minutesinteger · int32

        Required

        What the page quotes for collection, in minutes.

        ≥ 0

      • versioninteger · int64

        Required

        The location's version, which a change is made over (If-Match).

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 409

      The request conflicts with current state — a uniqueness constraint, or an attempt to mutate an order that is already completed or voided.

      Unlike 412, re-reading and retrying unchanged will not resolve it; the request itself has to change.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 412

      The If-Match version did not match the resource's current version: someone else wrote since you read.

      This is the expected, healthy outcome of two clients editing the same record — not an error condition to suppress. Re-read the resource, re-apply your change on top of the new state, and retry with the fresh ETag.

    • 415

      The request Content-Type is not supported. This API accepts application/json on all mutations.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

  15. POST/v1/locations/{id}/orders/calculate

    Calculate an order

    No. calculateLocationOrderAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    Prices a guest's basket against the location's catalog as it stands, storing nothing: the basket is the guest's own, kept in their browser, and nothing in it is trusted. Each line comes back with its name, the modifiers chosen and what it costs, or why it can't be ordered now (sold out, a choice no longer offered); the totals count only the lines that can. Square's CalculateOrder.

    can_check_out says whether this basket could be ordered now: the location is taking orders and no line or the basket itself has a problem. Placing the order prices it again.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    Request body application/json · CalculateOrderRequest

    • fulfillment_typestring · enum

      How the order will leave the building, which a tax rule may be keyed by. Absent is collection.

      pickupdelivery

    • linesarray of BasketLine

      Required

      ≤ 50 items

      • modifier_idsarray of string · uuid

        ≤ 50 items

      • notestring

        ≤ 200 chars

      • product_idstring · uuid

        Required

      • quantityQuantity

        Required

        How much of something, as a decimal string in the unit_of_measure beside it (each where there is none), as Square's quantity is: three croissants are "3", 1.4 kg of beans is "1.4". A string because a JSON number is a binary float to most parsers.

        It has at most as many decimal places as its unit's base unit holds — three in each, g and ml, six in kg and l — and a finer one is refused, never rounded. Tenvelo holds every quantity as an integer of that base unit (thousandths of an each, milligrams, microlitres; docs/decisions/0063); a client that computes with one should read the digits the same way, never through a float.

        ≤ 26 chars · pattern ^-?(0|[1-9][0-9]*)(\.[0-9]{1,6})?$

      • variant_idstring · uuid

    Responses

    • 200

      The basket, priced.

      CalculatedOrder · application/json
      • can_check_outboolean

        Required

        Whether this basket could be ordered now.

      • delivery_feeMoney

        Nullable

        The venue's delivery charge on a delivered order, absent when the basket is collection or the venue charges none. Part of the total; carries no tax in this version.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • linesarray of CalculatedOrderLine

        Required

        One per line sent, in the order sent.

        • idstring · uuid

          The line's own id, what a guest paying for specific items names back. Absent on a basket not yet placed.

        • namestring

          Required

          What the guest asked for, as the catalog names it now.

        • discountLineDiscount

          Why a line costs less than its catalog price, as it was applied.

          • namestring

            Required

          • amountMoney

            Required

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

        • modifiersarray of string

          Required

          The names of the modifiers chosen.

        • notestring
        • problemstring

          Why the line can't be ordered now. Absent when it can.

        • product_idstring · uuid

          Absent on a line rung up on a till without a product.

        • quantityQuantity

          Required

          How much of something, as a decimal string in the unit_of_measure beside it (each where there is none), as Square's quantity is: three croissants are "3", 1.4 kg of beans is "1.4". A string because a JSON number is a binary float to most parsers.

          It has at most as many decimal places as its unit's base unit holds — three in each, g and ml, six in kg and l — and a finer one is refused, never rounded. Tenvelo holds every quantity as an integer of that base unit (thousandths of an each, milligrams, microlitres; docs/decisions/0063); a client that computes with one should read the digits the same way, never through a float.

          ≤ 26 chars · pattern ^-?(0|[1-9][0-9]*)(\.[0-9]{1,6})?$

        • settledboolean

          Whether an earlier payment settled this line, so a guest paying for specific items cannot choose it again. False until a payment names the line.

        • totalMoney

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

      • problemsarray of string

        Required

        Why the basket as a whole can't be ordered, when it is not about one line.

      • subtotalMoney

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • tax_inclusiveboolean

        Required

        Whether every price shown already includes its tax.

      • tax_totalMoney

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • totalMoney

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 415

      The request Content-Type is not supported. This API accepts application/json on all mutations.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  16. GET/v1/locations/{id}/orders/{token}

    Get an order by its link

    No. getLocationOrderAuth no token

    Public: the link is the credential (docs/decisions/0113).

    Where a guest's order stands, what is in it and when it will be ready. The link is the credential, so a wrong one is a 404, and so is one for another location's order.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • tokenpath · string

      Required

      The order's link, as checkout or its confirmation gave it to the guest. It is the credential.

    Responses

    • 200

      The order.

      OrderStatus · application/json
      • customer_namestring

        Required

        The name the counter calls out.

      • linesarray of CalculatedOrderLine

        Required

        What was ordered. Empty for a moment after placing, until the order is on the books.

        • idstring · uuid

          The line's own id, what a guest paying for specific items names back. Absent on a basket not yet placed.

        • namestring

          Required

          What the guest asked for, as the catalog names it now.

        • discountLineDiscount

          Why a line costs less than its catalog price, as it was applied.

          • namestring

            Required

          • amountMoney

            Required

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

        • modifiersarray of string

          Required

          The names of the modifiers chosen.

        • notestring
        • problemstring

          Why the line can't be ordered now. Absent when it can.

        • product_idstring · uuid

          Absent on a line rung up on a till without a product.

        • quantityQuantity

          Required

          How much of something, as a decimal string in the unit_of_measure beside it (each where there is none), as Square's quantity is: three croissants are "3", 1.4 kg of beans is "1.4". A string because a JSON number is a binary float to most parsers.

          It has at most as many decimal places as its unit's base unit holds — three in each, g and ml, six in kg and l — and a finer one is refused, never rounded. Tenvelo holds every quantity as an integer of that base unit (thousandths of an each, milligrams, microlitres; docs/decisions/0063); a client that computes with one should read the digits the same way, never through a float.

          ≤ 26 chars · pattern ^-?(0|[1-9][0-9]*)(\.[0-9]{1,6})?$

        • settledboolean

          Whether an earlier payment settled this line, so a guest paying for specific items cannot choose it again. False until a payment names the line.

        • totalMoney

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

      • locationOrderLocation

        Required

        The location an order is collected from.

        • namestring

          Required

        • addressAddress

          A postal address.

          The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

          The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

          • address_line_1string

            Required

            First line of the address — street number, street name, building name.

            ≤ 255 chars

          • address_line_2string

            Second line of the address, if any.

            ≤ 255 chars

          • address_line_3string

            Third line of the address, if any.

            ≤ 255 chars

          • administrative_district_level_1string

            A civil entity within the country. The state in the US; the county in the UK.

            ≤ 128 chars

          • administrative_district_level_2string

            A civil entity within administrative_district_level_1.

            ≤ 128 chars

          • countryCountry

            Required

            ISO 3166-1 alpha-2 country code.

            ZZ is the unknown/unspecified placeholder.

            One of 250 values; see the schema.

          • localitystring

            The city or town.

            ≤ 128 chars

          • postal_codestring

            The postal or ZIP code.

            ≤ 32 chars

          • sublocalitystring

            A civil region within the locality, if any.

            ≤ 128 chars

        • business_namestring

          Required

        • currencyCurrency

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

        • phone_numberstring
        • timezonestring

          Required

          The location's IANA time zone, which its clock times are told in.

      • pickup_atstring · date-time

        When it will be ready to collect, once the location has said.

      • rejection_reasonstring · enum

        Why the location turned it down, when it did.

        sold_outclosedtoo_busyothertimed_out

      • statusstring · enum

        Required

        received is waiting for the location to accept it; preparing is accepted and being made; ready is waiting at the counter; collected is done. rejected is turned down by the location, and canceled called off.

        receivedpreparingreadycollectedrejectedcanceled

      • totalMoney

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  17. POST/v1/locations/{id}/orders/{token}/pay

    Pay an order by its link

    No. payOnlineOrderAuth no token

    Public: the link is the credential (docs/decisions/0113).

    Charges the guest's card against the open order the link names, through the processor the business's card-not-present account names. The card is what the guest typed on the page — the number, expiry and CVC — and the details are validated here and sent on to the processor, never stored (the same rules as keying a card on a virtual till, virtual-till item 3). A processor's own card field may name a token instead.

    Without an amount it pays all that remains. The app mints the id; a retry answers the same charge and never takes the card twice. A declined or unknown charge leaves the order open. A wrong link, or one for another location's order, is a 404.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • tokenpath · string

      Required

      The order's link, as checkout or its confirmation gave it to the guest. It is the credential.

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Request body application/json · PayOnlineOrder

    • idstring · uuid

      Required

      Minted by the app when the guest starts paying; a retry names the same charge.

    • amountMoney

      A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

      The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

      Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

      • amountinteger · int64

        Required

        The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

      • currencyCurrency

        Required

        ISO 4217 currency code.

        Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

        One of 182 values; see the schema.

    • cardstring

      A processor's token for the card, never a card number. Not with card_details.

      1–256 chars

    • card_detailsCard details

      A card keyed in rather than tokenised: what somebody reads off a card and types at the till or over the phone. The details travel to the processor the payment account names and are never stored by the API — no card number is written down, logged or returned (one of card and card_details is required on a charge; a card read by a terminal or a guest page arrives as a token instead).

      • cvcstring

        Required

        The card verification code on the back.

        3–4 chars

      • expiry_monthinteger

        Required

        The month the card expires, 1-12.

        1–12

      • expiry_yearinteger

        Required

        The year the card expires, as two or four digits (26 or 2026).

        ≥ 0

      • holder_namestring

        The name as it appears on the card, when the processor wants it.

        ≤ 255 chars

      • numberstring

        Required

        The card number, digits only; the server checks Luhn before the processor is asked.

        12–19 chars

    Responses

    • 200

      The charge, and what came of it.

      OrderPayment · application/json
      • idstring · uuid

        Required

      • amountMoney

        Required

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • statusstring · enum

        Required

        pendingapproveddeclinedunknown

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 415

      The request Content-Type is not supported. This API accepts application/json on all mutations.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  18. POST/v1/locations/{id}/pause

    Pause online ordering at a location

    No. pauseLocationAuth ordering:write

    Stops the location taking new orders from its ordering page and channels: guests see the menu and cannot order, and nothing else about the location changes. The delivery platforms' "pause the store". Any person at the location may, not only a manager — pausing is a call made on the floor in a rush — or an integration with the ordering:write scope. No If-Match: the switch touches only itself, so it cannot lose a change somebody made to the location.

    Parameters

    • idpath · string · uuid

      Required

      UUIDv7 of the resource.

      For resources a device can originate — orders, and their line items — this id is minted by the client before the record is ever synced, which is what makes an offline create idempotent.

    Responses

    • 200

      The location, paused.

      Location · application/json
      • idstring · uuid

        Required

        UUIDv7 identifying the location.

      • typestring · enum

        Required

        mobile locations — market stalls, food vans — are expected to spend meaningful time offline, and are the reason the sync contract exists.

        physicalmobile

      • namestring

        Required

        Human-readable name, unique within the merchant. Appears in the dashboard and on receipts.

        1–255 chars

      • addressAddress

        A postal address.

        The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

        The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

        • address_line_1string

          Required

          First line of the address — street number, street name, building name.

          ≤ 255 chars

        • address_line_2string

          Second line of the address, if any.

          ≤ 255 chars

        • address_line_3string

          Third line of the address, if any.

          ≤ 255 chars

        • administrative_district_level_1string

          A civil entity within the country. The state in the US; the county in the UK.

          ≤ 128 chars

        • administrative_district_level_2string

          A civil entity within administrative_district_level_1.

          ≤ 128 chars

        • countryCountry

          Required

          ISO 3166-1 alpha-2 country code.

          ZZ is the unknown/unspecified placeholder.

          One of 250 values; see the schema.

        • localitystring

          The city or town.

          ≤ 128 chars

        • postal_codestring

          The postal or ZIP code.

          ≤ 32 chars

        • sublocalitystring

          A civil region within the locality, if any.

          ≤ 128 chars

      • auto_close_default_tip_percentagePercentage

        A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

        A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

        pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

      • auto_close_enabledboolean

        On, when this location's day closes, every open tab holding a card is settled with auto_close_default_tip_percentage; a tab with no card is left open and flagged left-overnight (tabs item 9).

      • booking_hoursarray of DaypartWindow

        The hours this location takes bookings, in its own timezone. Empty takes none. Absent from a write leaves them as they are.

        ≤ 28 items

        • daysarray of integer

          The weekdays this window opens on, 1 (Monday) through 7 (Sunday). An empty or absent list is every day.

          ≤ 7 items

        • end_minuteinteger

          Required

          1–1440

        • start_minuteinteger

          Required

          0–1439

      • break_threshold_minutesinteger · int32

        How long a shift at this location may run before a break is expected, in minutes. Zero disables the rule. Replaces the hard-coded six hours in the timesheet.

        ≥ 0 · default 360

      • business_day_start_local_timestring

        When this location's trading day begins, as a wall-clock time in its timezone (RFC 3339 partial-time, in the shape Square uses for start_local_time). A sale before it belongs to the previous business day, so a bar's 00:30 round counts towards last night's takings rather than today's.

        Defaults to 04:00, as Toast's closeout hour does: nothing that opens before four in the morning is affected, and every late-night venue is. Changing it affects sales from then on; days already traded keep the business date they were given.

        pattern ^([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$ · default 04:00:00

      • business_emailstring · email

        The address a guest's reply to an email this venue sent should reach: the Reply-To on the guest messages this location's emails send. Empty means a reply goes to the platform, which answers for the venue.

        ≤ 254 chars

      • business_hoursarray of DaypartWindow

        The hours this location trades, in its own timezone, which the marketplace shows as open or closed. Apart from booking_hours. Absent from a write leaves them as they are.

        ≤ 8 items

        • daysarray of integer

          The weekdays this window opens on, 1 (Monday) through 7 (Sunday). An empty or absent list is every day.

          ≤ 7 items

        • end_minuteinteger

          Required

          1–1440

        • start_minuteinteger

          Required

          0–1439

      • cash_stepMoney

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • coordinatesCoordinates

        Nullable

        Where the location is, placed by the merchant, which the marketplace sorts guests' results by. null until placed. Absent from a write leaves it as it is.

        • latitudenumber · double

          Required

          -90–90

        • longitudenumber · double

          Required

          -180–180

      • created_atTimestamp

        RequiredRead only

        Server-assigned RFC 3339 timestamp, always UTC.

        Server-assigned because device clocks drift and cannot be trusted for ordering — a till that has been powered off for a week may come back with a clock hours out. Where the device's own view of time matters it is carried separately in client_created_at.

      • currencyCurrency

        Required

        ISO 4217 currency code.

        Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

        One of 182 values; see the schema.

      • descriptionstring

        What the location says about itself on the marketplace. Absent from a write leaves it as it is.

        ≤ 280 chars

      • favoritesarray of string · uuid

        A shop's favourites, Square's Favorites and Toast's speed menu: up to twenty-four of its products, in this order, which a till in retail shows first, before the catalogue. Empty means the catalogue alone. Chosen in the back office; a device never writes it.

        ≤ 24 items · default []

      • kds_amber_minutesinteger · int32

        How long a kitchen ticket may wait (in minutes) before a kitchen display colours it amber. A location setting; the till paints from it.

        ≥ 1 · default 10

      • kds_red_minutesinteger · int32

        How long a kitchen ticket may wait (in minutes) before a kitchen display colours it red. A location setting; the till paints from it.

        ≥ 1 · default 20

      • labor_budgetMoney

        Nullable

        What a week's labor here is planned to cost, which the rota compares against. null sets none. Absent from a write leaves it as it is.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • labor_target_percentagePercentage

        Nullable

        What labor here should cost as a share of net sales, which Home and the labor report set the day's cost against. null sets none. Absent from a write leaves it as it is.

        pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

      • language_codeLanguageCode

        IETF BCP 47 language tag.

        Used for receipts, dashboard copy and buyer-facing text.

        One of 30 values; see the schema.

      • merchant_idstring · uuid

        RequiredRead only

        The owning merchant. Read-only and derived from the caller's token — a location can never be moved between merchants.

      • min_break_minutesinteger · int32

        The least a break that is taken should be, in minutes. A shift with a break shorter than this still counts as missed.

        ≥ 0 · default 0

      • online_bookingOnlineBooking

        Whether guests may book this location themselves on its booking page, how far ahead and for how many, and how much of the room is kept for walk-ins. Absent from a write leaves it as it is.

        • days_aheadinteger · int32

          Required

          0–365

        • deposit_per_personMoney

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • enabledboolean

          Required

        • max_party_sizeinteger · int32

          Required

          The largest party a guest may book online. 0 is no limit.

          0–100

        • waitlist_enabledboolean

          Whether guests may join this location's waitlist from its own page. Distinct from enabled: a venue may take bookings online and not queue walk-ins from the web, or queue them and take no bookings. Absent from a write leaves it as it is.

        • walk_in_percentagePercentage

          Required

          A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

          A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

          pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

      • ordering_auto_acceptboolean

        Read only

        Whether an order from the ordering page is accepted as it arrives, rather than waiting for somebody to take it on. Changed on the ordering settings, not by writing the location.

        default false

      • ordering_enabledboolean

        Read only

        Whether guests can order from this location's ordering page. Changed on the ordering settings, not by writing the location.

        default false

      • ordering_handlestring

        Read only

        The ordering page's name: its subdomain on the guest ordering site. Absent until one is chosen. Changed on the ordering settings, not by writing the location.

        ≤ 63 chars

      • ordering_pausedboolean

        When true, a channel's new open orders are refused — the kitchen could not take another one. The till keeps selling regardless, and the setting is carried on the change feed so every surface hears it without a poll.

        default false

      • ordering_prep_time_minutesinteger · int32

        What an ordering page quotes for collection, in minutes. A location setting.

        ≥ 0 · default 0

      • overtime_threshold_hoursinteger · int32

        Hours a member may work in a week here before the rota warns. 0 is no threshold. Absent from a write leaves it as it is.

        0–168

      • phone_numberstring

        Contact number in E.164 format.

        ≤ 32 chars

      • profilestring · enum

        Nullable

        What this location trades as, so the till and the back office show or default what that trade uses. Absent means show everything, the current behaviour. Presentation and defaults only, never enforcement.

        hospitalityretail

      • return_window_daysinteger · int32

        Nullable

        This location's own returns window, in days (retail item 10). Absent means the merchant's window applies — a merchant whose sites differ sets it here, where the customer is told it. Zero is a deliberate no-window at this site.

        ≥ 0

      • service_chargeServiceCharge

        Nullable

        This location's discretionary service charge, added to the bill before anyone pays (order-ledger item 9). null means the location charges none.

        • amountMoney

          Nullable

          The charge as a fixed amount per bill. Exactly one of percentage and amount is set.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • discretionaryboolean

          Required

          Whether the guest may decline the charge. A charge that cannot be declined is a mandatory one and is taxed as such.

          default true

        • eat_in_onlyboolean

          Required

          Whether the charge applies to on-premises (eat-in) fulfilments only, or to every fulfilment.

          default false

        • percentagePercentage

          A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

          A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

          pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

        • tax_class_idstring · uuid

          Nullable

          The tax class this location's service charge is taxed under (decision record 0054), resolved by the same dated rules as goods and keyed by fulfilment type and date. A market's pack sets it to the outside-scope/zero class for a discretionary charge and the standard class for a mandatory one. Null means the charge is not taxed.

      • service_periodsarray of ServicePeriod

        The named services in a day, such as lunch and dinner, each with its own turn times and pacing. Absent from a write leaves them as they are.

        ≤ 20 items

        • namestring

          Required

          1–64 chars

        • daysarray of integer

          The weekdays it runs, 1 (Monday) to 7 (Sunday). Empty or absent is every day.

          ≤ 7 items

        • end_minuteinteger

          Required

          0–1440

        • pacing_coversinteger · int32

          The most covers that may arrive in one slot during this service. 0 is no cap.

          ≥ 0

        • start_minuteinteger

          Required

          0–1439

        • turn_timesarray of TurnTime

          How long a party stays during this service. Empty uses the location's.

          ≤ 20 items

          • max_party_sizeinteger · int32

            Required

            1–100

          • minutesinteger · int32

            Required

            1–1440

      • statusstring · enum

        Required

        activeinactive

      • tax_registration_numberstring

        This venue's own tax registration (a VAT number, say), as a receipt that prints this address carries it. Absent, the merchant's number applies — right for a single-country merchant and a franchise, wrong for a multi-country estate, where the taxpayer is per country and the merchant's number must not print above a foreign address (receipts-and-printing item 21).

        ≤ 32 chars

      • timezoneTimezone

        Required

        IANA time zone identifier.

        Used to resolve a location's business day for reporting and settlement.

        One of 348 values; see the schema.

      • tip_policystring · enum

        Whether this location's terminal prompts the guest for a tip, and what it offers. The till sends it with a card checkout so the terminal offers a tip, and the tip the guest adds lands on the payment. off takes the amount with no prompt; allow lets the guest add one on the terminal, using the options configured there.

        offallow

        default off

      • tip_presetsarray of Percentage

        What a card checkout at this location offers when it prompts for a tip, lowest first and none preselected: the till's tender sheet and a guest paying from their own phone both offer exactly these, and the charge applies the tapped one without rounding anywhere else. ["18", "20", "25"] is the platform default, which is what a location opens with; the merchant may change it like any other location setting.

        ≥ 1 items · ≤ 4 items · default [18 20 25]

      • turn_timesarray of TurnTime

        How long a party holds its table, by size: each entry covers parties up to its max_party_size, in order. Absent from a write leaves them as they are.

        ≤ 20 items

        • max_party_sizeinteger · int32

          Required

          1–100

        • minutesinteger · int32

          Required

          1–1440

      • updated_atTimestamp

        RequiredRead only

        Server-assigned RFC 3339 timestamp, always UTC.

        Server-assigned because device clocks drift and cannot be trusted for ordering — a till that has been powered off for a week may come back with a clock hours out. Where the device's own view of time matters it is carried separately in client_created_at.

      • versionVersion

        RequiredRead only

        Optimistic concurrency version, raised by the server on every write. A version is never lower than one already returned for the resource, though it may rise by more than one.

        Returned in the ETag response header as well as in the body. Send it back in If-Match on an update and the write is rejected with 412 if anyone else has written since — which is what stops two tills silently overwriting each other's edit to the same product when both come back online at once.

        ≥ 1

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  19. GET/v1/locations/{id}/pickup-times

    Get the times an order can be collected

    No. getLocationPickupTimesAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    The soonest an order placed now could be ready, from the location's own prep time, and the later times a guest may choose instead. Worked out here, at the location's clock, so every guest is offered the same slots the kitchen plans by.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    Responses

    • 200

      The times.

      PickupTimes · application/json
      • sooneststring · date-time

        Required

        About when an order placed now, for as soon as possible, will be ready.

      • timesarray of string · date-time

        Required

        The later times a guest may choose, earliest first.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  20. GET/v1/locations/{id}/popular-items

    Get what people order at the location

    No. getLocationPopularItemsAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    The marketplace's "What people order" preview (online-ordering item 19): the products a location's guests bought in the last month, counted from completed sales — the most sold first, up to four, each with what the storefront charges today. Everything is derived on read; nothing about it is stored. An item a guest cannot order today (86'd, or gone from the menu) is not promised. The count is of lines as the sale completed them: no gift card, and no line that names no product.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    Responses

    • 200

      The location's popular items.

      PopularItems · application/json
      • itemsarray of PopularItem

        Required

        ≤ 4 items

        • namestring

          Required

        • priceMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • product_idstring · uuid

          Required

        • soldinteger · int64

          Required

          ≥ 1

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  21. GET/v1/locations/{id}/products/{product_id}

    Get a product

    No. getLocationProductAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    One product as a guest chooses it: its variants with their prices, and each modifier group with how many of its modifiers a guest must and may choose. The same for every guest of the location, so cacheable as the catalog is. A product the location does not sell online is a 404.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • product_idpath · string · uuid

      Required

      The product, by its id.

    • If-None-Matchheader · string

      The ETag of a copy the caller holds. If it is still current, the answer is 304 with no body (RFC 9110 §13.1.2).

    Responses

    • 200

      The product.

      OnlineProduct · application/json
      • idstring · uuid

        Required

      • namestring

        Required

      • allergensarray of string

        Required

      • availableboolean

        Required

      • descriptionstring
      • image_urlstring · uri
      • modifier_groupsarray of OnlineModifierGroup

        Required

        The modifier groups offered with it, each with at least one modifier.

        • idstring · uuid

          Required

        • namestring

          Required

        • max_selectionsinteger

          Required

          How many a guest may choose. Zero for no limit.

          ≥ 0

        • min_selectionsinteger

          Required

          How many a guest must choose. Zero for an optional group.

          ≥ 0

        • modifiersarray of OnlineModifier

          Required

          • idstring · uuid

            Required

          • namestring

            Required

          • price_deltaMoney

            Required

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

      • priceMoney

        Required

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • variantsarray of OnlineProductVariant

        Required

        The variants a guest chooses one of. Empty when there are none.

        • idstring · uuid

          Required

        • namestring

          Required

        • priceMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

    • 304

      The copy the caller holds is current (RFC 9110 §15.4.5).

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  22. POST/v1/locations/{id}/resume

    Resume online ordering at a location

    No. resumeLocationAuth ordering:write

    Lets a paused location take orders from its ordering page and channels again. Who may is who may pause: any person at the location, or an integration with the ordering:write scope.

    Parameters

    • idpath · string · uuid

      Required

      UUIDv7 of the resource.

      For resources a device can originate — orders, and their line items — this id is minted by the client before the record is ever synced, which is what makes an offline create idempotent.

    Responses

    • 200

      The location, taking orders.

      Location · application/json
      • idstring · uuid

        Required

        UUIDv7 identifying the location.

      • typestring · enum

        Required

        mobile locations — market stalls, food vans — are expected to spend meaningful time offline, and are the reason the sync contract exists.

        physicalmobile

      • namestring

        Required

        Human-readable name, unique within the merchant. Appears in the dashboard and on receipts.

        1–255 chars

      • addressAddress

        A postal address.

        The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

        The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

        • address_line_1string

          Required

          First line of the address — street number, street name, building name.

          ≤ 255 chars

        • address_line_2string

          Second line of the address, if any.

          ≤ 255 chars

        • address_line_3string

          Third line of the address, if any.

          ≤ 255 chars

        • administrative_district_level_1string

          A civil entity within the country. The state in the US; the county in the UK.

          ≤ 128 chars

        • administrative_district_level_2string

          A civil entity within administrative_district_level_1.

          ≤ 128 chars

        • countryCountry

          Required

          ISO 3166-1 alpha-2 country code.

          ZZ is the unknown/unspecified placeholder.

          One of 250 values; see the schema.

        • localitystring

          The city or town.

          ≤ 128 chars

        • postal_codestring

          The postal or ZIP code.

          ≤ 32 chars

        • sublocalitystring

          A civil region within the locality, if any.

          ≤ 128 chars

      • auto_close_default_tip_percentagePercentage

        A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

        A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

        pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

      • auto_close_enabledboolean

        On, when this location's day closes, every open tab holding a card is settled with auto_close_default_tip_percentage; a tab with no card is left open and flagged left-overnight (tabs item 9).

      • booking_hoursarray of DaypartWindow

        The hours this location takes bookings, in its own timezone. Empty takes none. Absent from a write leaves them as they are.

        ≤ 28 items

        • daysarray of integer

          The weekdays this window opens on, 1 (Monday) through 7 (Sunday). An empty or absent list is every day.

          ≤ 7 items

        • end_minuteinteger

          Required

          1–1440

        • start_minuteinteger

          Required

          0–1439

      • break_threshold_minutesinteger · int32

        How long a shift at this location may run before a break is expected, in minutes. Zero disables the rule. Replaces the hard-coded six hours in the timesheet.

        ≥ 0 · default 360

      • business_day_start_local_timestring

        When this location's trading day begins, as a wall-clock time in its timezone (RFC 3339 partial-time, in the shape Square uses for start_local_time). A sale before it belongs to the previous business day, so a bar's 00:30 round counts towards last night's takings rather than today's.

        Defaults to 04:00, as Toast's closeout hour does: nothing that opens before four in the morning is affected, and every late-night venue is. Changing it affects sales from then on; days already traded keep the business date they were given.

        pattern ^([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]$ · default 04:00:00

      • business_emailstring · email

        The address a guest's reply to an email this venue sent should reach: the Reply-To on the guest messages this location's emails send. Empty means a reply goes to the platform, which answers for the venue.

        ≤ 254 chars

      • business_hoursarray of DaypartWindow

        The hours this location trades, in its own timezone, which the marketplace shows as open or closed. Apart from booking_hours. Absent from a write leaves them as they are.

        ≤ 8 items

        • daysarray of integer

          The weekdays this window opens on, 1 (Monday) through 7 (Sunday). An empty or absent list is every day.

          ≤ 7 items

        • end_minuteinteger

          Required

          1–1440

        • start_minuteinteger

          Required

          0–1439

      • cash_stepMoney

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • coordinatesCoordinates

        Nullable

        Where the location is, placed by the merchant, which the marketplace sorts guests' results by. null until placed. Absent from a write leaves it as it is.

        • latitudenumber · double

          Required

          -90–90

        • longitudenumber · double

          Required

          -180–180

      • created_atTimestamp

        RequiredRead only

        Server-assigned RFC 3339 timestamp, always UTC.

        Server-assigned because device clocks drift and cannot be trusted for ordering — a till that has been powered off for a week may come back with a clock hours out. Where the device's own view of time matters it is carried separately in client_created_at.

      • currencyCurrency

        Required

        ISO 4217 currency code.

        Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

        One of 182 values; see the schema.

      • descriptionstring

        What the location says about itself on the marketplace. Absent from a write leaves it as it is.

        ≤ 280 chars

      • favoritesarray of string · uuid

        A shop's favourites, Square's Favorites and Toast's speed menu: up to twenty-four of its products, in this order, which a till in retail shows first, before the catalogue. Empty means the catalogue alone. Chosen in the back office; a device never writes it.

        ≤ 24 items · default []

      • kds_amber_minutesinteger · int32

        How long a kitchen ticket may wait (in minutes) before a kitchen display colours it amber. A location setting; the till paints from it.

        ≥ 1 · default 10

      • kds_red_minutesinteger · int32

        How long a kitchen ticket may wait (in minutes) before a kitchen display colours it red. A location setting; the till paints from it.

        ≥ 1 · default 20

      • labor_budgetMoney

        Nullable

        What a week's labor here is planned to cost, which the rota compares against. null sets none. Absent from a write leaves it as it is.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • labor_target_percentagePercentage

        Nullable

        What labor here should cost as a share of net sales, which Home and the labor report set the day's cost against. null sets none. Absent from a write leaves it as it is.

        pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

      • language_codeLanguageCode

        IETF BCP 47 language tag.

        Used for receipts, dashboard copy and buyer-facing text.

        One of 30 values; see the schema.

      • merchant_idstring · uuid

        RequiredRead only

        The owning merchant. Read-only and derived from the caller's token — a location can never be moved between merchants.

      • min_break_minutesinteger · int32

        The least a break that is taken should be, in minutes. A shift with a break shorter than this still counts as missed.

        ≥ 0 · default 0

      • online_bookingOnlineBooking

        Whether guests may book this location themselves on its booking page, how far ahead and for how many, and how much of the room is kept for walk-ins. Absent from a write leaves it as it is.

        • days_aheadinteger · int32

          Required

          0–365

        • deposit_per_personMoney

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • enabledboolean

          Required

        • max_party_sizeinteger · int32

          Required

          The largest party a guest may book online. 0 is no limit.

          0–100

        • waitlist_enabledboolean

          Whether guests may join this location's waitlist from its own page. Distinct from enabled: a venue may take bookings online and not queue walk-ins from the web, or queue them and take no bookings. Absent from a write leaves it as it is.

        • walk_in_percentagePercentage

          Required

          A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

          A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

          pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

      • ordering_auto_acceptboolean

        Read only

        Whether an order from the ordering page is accepted as it arrives, rather than waiting for somebody to take it on. Changed on the ordering settings, not by writing the location.

        default false

      • ordering_enabledboolean

        Read only

        Whether guests can order from this location's ordering page. Changed on the ordering settings, not by writing the location.

        default false

      • ordering_handlestring

        Read only

        The ordering page's name: its subdomain on the guest ordering site. Absent until one is chosen. Changed on the ordering settings, not by writing the location.

        ≤ 63 chars

      • ordering_pausedboolean

        When true, a channel's new open orders are refused — the kitchen could not take another one. The till keeps selling regardless, and the setting is carried on the change feed so every surface hears it without a poll.

        default false

      • ordering_prep_time_minutesinteger · int32

        What an ordering page quotes for collection, in minutes. A location setting.

        ≥ 0 · default 0

      • overtime_threshold_hoursinteger · int32

        Hours a member may work in a week here before the rota warns. 0 is no threshold. Absent from a write leaves it as it is.

        0–168

      • phone_numberstring

        Contact number in E.164 format.

        ≤ 32 chars

      • profilestring · enum

        Nullable

        What this location trades as, so the till and the back office show or default what that trade uses. Absent means show everything, the current behaviour. Presentation and defaults only, never enforcement.

        hospitalityretail

      • return_window_daysinteger · int32

        Nullable

        This location's own returns window, in days (retail item 10). Absent means the merchant's window applies — a merchant whose sites differ sets it here, where the customer is told it. Zero is a deliberate no-window at this site.

        ≥ 0

      • service_chargeServiceCharge

        Nullable

        This location's discretionary service charge, added to the bill before anyone pays (order-ledger item 9). null means the location charges none.

        • amountMoney

          Nullable

          The charge as a fixed amount per bill. Exactly one of percentage and amount is set.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • discretionaryboolean

          Required

          Whether the guest may decline the charge. A charge that cannot be declined is a mandatory one and is taxed as such.

          default true

        • eat_in_onlyboolean

          Required

          Whether the charge applies to on-premises (eat-in) fulfilments only, or to every fulfilment.

          default false

        • percentagePercentage

          A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

          A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

          pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

        • tax_class_idstring · uuid

          Nullable

          The tax class this location's service charge is taxed under (decision record 0054), resolved by the same dated rules as goods and keyed by fulfilment type and date. A market's pack sets it to the outside-scope/zero class for a discretionary charge and the standard class for a mandatory one. Null means the charge is not taxed.

      • service_periodsarray of ServicePeriod

        The named services in a day, such as lunch and dinner, each with its own turn times and pacing. Absent from a write leaves them as they are.

        ≤ 20 items

        • namestring

          Required

          1–64 chars

        • daysarray of integer

          The weekdays it runs, 1 (Monday) to 7 (Sunday). Empty or absent is every day.

          ≤ 7 items

        • end_minuteinteger

          Required

          0–1440

        • pacing_coversinteger · int32

          The most covers that may arrive in one slot during this service. 0 is no cap.

          ≥ 0

        • start_minuteinteger

          Required

          0–1439

        • turn_timesarray of TurnTime

          How long a party stays during this service. Empty uses the location's.

          ≤ 20 items

          • max_party_sizeinteger · int32

            Required

            1–100

          • minutesinteger · int32

            Required

            1–1440

      • statusstring · enum

        Required

        activeinactive

      • tax_registration_numberstring

        This venue's own tax registration (a VAT number, say), as a receipt that prints this address carries it. Absent, the merchant's number applies — right for a single-country merchant and a franchise, wrong for a multi-country estate, where the taxpayer is per country and the merchant's number must not print above a foreign address (receipts-and-printing item 21).

        ≤ 32 chars

      • timezoneTimezone

        Required

        IANA time zone identifier.

        Used to resolve a location's business day for reporting and settlement.

        One of 348 values; see the schema.

      • tip_policystring · enum

        Whether this location's terminal prompts the guest for a tip, and what it offers. The till sends it with a card checkout so the terminal offers a tip, and the tip the guest adds lands on the payment. off takes the amount with no prompt; allow lets the guest add one on the terminal, using the options configured there.

        offallow

        default off

      • tip_presetsarray of Percentage

        What a card checkout at this location offers when it prompts for a tip, lowest first and none preselected: the till's tender sheet and a guest paying from their own phone both offer exactly these, and the charge applies the tapped one without rounding anywhere else. ["18", "20", "25"] is the platform default, which is what a location opens with; the merchant may change it like any other location setting.

        ≥ 1 items · ≤ 4 items · default [18 20 25]

      • turn_timesarray of TurnTime

        How long a party holds its table, by size: each entry covers parties up to its max_party_size, in order. Absent from a write leaves them as they are.

        ≤ 20 items

        • max_party_sizeinteger · int32

          Required

          1–100

        • minutesinteger · int32

          Required

          1–1440

      • updated_atTimestamp

        RequiredRead only

        Server-assigned RFC 3339 timestamp, always UTC.

        Server-assigned because device clocks drift and cannot be trusted for ordering — a till that has been powered off for a week may come back with a clock hours out. Where the device's own view of time matters it is carried separately in client_created_at.

      • versionVersion

        RequiredRead only

        Optimistic concurrency version, raised by the server on every write. A version is never lower than one already returned for the resource, though it may rise by more than one.

        Returned in the ETag response header as well as in the body. Send it back in If-Match on an update and the write is rejected with 412 if anyone else has written since — which is what stops two tills silently overwriting each other's edit to the same product when both come back online at once.

        ≥ 1

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  23. GET/v1/locations/{id}/tables/{secret}

    Get a table by its code

    No. getTableBillAuth no token

    The table a guest scanned: what is open on it, as the till has it, and what the guest may do there. The code is the credential, so one nobody issued is a 404, and so is one for another location's table or a location that doesn't take orders at the table.

    With split_count, the payment options are worked out for one of that many equal shares of what remains.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • secretpath · string

      Required

      The secret in the table's QR code. It is the credential.

    • split_countquery · integer

      How many people are sharing what remains.

    Responses

    • 200

      The table.

      TableBill · application/json
      • namestring

        Required

        The table's name, as the room knows it.

      • can_orderboolean

        Required

        Whether the guest may order at the table now. Where nothing is open, only if the location lets a guest's order open the table.

      • card_holdTableHold

        The card a guest put down at a table, as the bill page shows it: an authorisation on the open order, never a capture, and never the card's number — the brand and the last four are the processor's word, as a payment shows them.

        • idstring · uuid

          Required

        • amountMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • card_brandstring

          The card's scheme, as the processor reported it — Visa, Mastercard.

        • card_last4string

          The last four digits of the card, as the processor reported them. Never the PAN.

        • statusstring · enum

          Required

          pendingunknownhelddeclinedfailedsettledvoidedexpired

      • locationOrderLocation

        Required

        The location an order is collected from.

        • namestring

          Required

        • addressAddress

          A postal address.

          The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

          The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

          • address_line_1string

            Required

            First line of the address — street number, street name, building name.

            ≤ 255 chars

          • address_line_2string

            Second line of the address, if any.

            ≤ 255 chars

          • address_line_3string

            Third line of the address, if any.

            ≤ 255 chars

          • administrative_district_level_1string

            A civil entity within the country. The state in the US; the county in the UK.

            ≤ 128 chars

          • administrative_district_level_2string

            A civil entity within administrative_district_level_1.

            ≤ 128 chars

          • countryCountry

            Required

            ISO 3166-1 alpha-2 country code.

            ZZ is the unknown/unspecified placeholder.

            One of 250 values; see the schema.

          • localitystring

            The city or town.

            ≤ 128 chars

          • postal_codestring

            The postal or ZIP code.

            ≤ 32 chars

          • sublocalitystring

            A civil region within the locality, if any.

            ≤ 128 chars

        • business_namestring

          Required

        • currencyCurrency

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

        • phone_numberstring
        • timezonestring

          Required

          The location's IANA time zone, which its clock times are told in.

      • orderTableOrder

        The order open on a table, as the till has it. Absent when nothing is open.

        • linesarray of CalculatedOrderLine

          Required

          • idstring · uuid

            The line's own id, what a guest paying for specific items names back. Absent on a basket not yet placed.

          • namestring

            Required

            What the guest asked for, as the catalog names it now.

          • discountLineDiscount

            Why a line costs less than its catalog price, as it was applied.

            • namestring

              Required

            • amountMoney

              Required

              A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

              The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

              Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

              • amountinteger · int64

                Required

                The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

              • currencyCurrency

                Required

                ISO 4217 currency code.

                Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

                One of 182 values; see the schema.

          • modifiersarray of string

            Required

            The names of the modifiers chosen.

          • notestring
          • problemstring

            Why the line can't be ordered now. Absent when it can.

          • product_idstring · uuid

            Absent on a line rung up on a till without a product.

          • quantityQuantity

            Required

            How much of something, as a decimal string in the unit_of_measure beside it (each where there is none), as Square's quantity is: three croissants are "3", 1.4 kg of beans is "1.4". A string because a JSON number is a binary float to most parsers.

            It has at most as many decimal places as its unit's base unit holds — three in each, g and ml, six in kg and l — and a finer one is refused, never rounded. Tenvelo holds every quantity as an integer of that base unit (thousandths of an each, milligrams, microlitres; docs/decisions/0063); a client that computes with one should read the digits the same way, never through a float.

            ≤ 26 chars · pattern ^-?(0|[1-9][0-9]*)(\.[0-9]{1,6})?$

          • settledboolean

            Whether an earlier payment settled this line, so a guest paying for specific items cannot choose it again. False until a payment names the line.

          • totalMoney

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

        • ready_to_payboolean

          Required

          Whether a server has been called to take payment, and nobody has taken one since.

        • remainingMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • totalMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

      • payment_optionsPaymentOptions

        How a guest may pay at the table from their phone. Absent when nothing is open, or the business takes no card here.

        • amountMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • processorstring

          Required

          The processor the card is taken by, and so whose card field the app shows.

        • split_countinteger

          How many equal shares amount is one of. Absent when the guest isn't sharing, or the bill can't be split that many ways.

          ≥ 2

        • tip_optionsarray of TipOption

          Required

          The tips offered, lowest first and none chosen, each worked out on amount.

          • percentagePercentage

            Required

            A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

            A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

            pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

          • tipMoney

            Required

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  24. POST/v1/locations/{id}/tables/{secret}/call

    Call a server to a table

    No. callServerAuth no token

    Asks for a server to come and take payment, shown on the tills as the order's ready_to_pay until somebody takes a payment. Calling again before then is the same call, and a table with nothing open is a 404 (no-open-order).

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • secretpath · string

      Required

      The secret in the table's QR code. It is the credential.

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Responses

    • 200

      The table, with the call made.

      TableBill · application/json
      • namestring

        Required

        The table's name, as the room knows it.

      • can_orderboolean

        Required

        Whether the guest may order at the table now. Where nothing is open, only if the location lets a guest's order open the table.

      • card_holdTableHold

        The card a guest put down at a table, as the bill page shows it: an authorisation on the open order, never a capture, and never the card's number — the brand and the last four are the processor's word, as a payment shows them.

        • idstring · uuid

          Required

        • amountMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • card_brandstring

          The card's scheme, as the processor reported it — Visa, Mastercard.

        • card_last4string

          The last four digits of the card, as the processor reported them. Never the PAN.

        • statusstring · enum

          Required

          pendingunknownhelddeclinedfailedsettledvoidedexpired

      • locationOrderLocation

        Required

        The location an order is collected from.

        • namestring

          Required

        • addressAddress

          A postal address.

          The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

          The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

          • address_line_1string

            Required

            First line of the address — street number, street name, building name.

            ≤ 255 chars

          • address_line_2string

            Second line of the address, if any.

            ≤ 255 chars

          • address_line_3string

            Third line of the address, if any.

            ≤ 255 chars

          • administrative_district_level_1string

            A civil entity within the country. The state in the US; the county in the UK.

            ≤ 128 chars

          • administrative_district_level_2string

            A civil entity within administrative_district_level_1.

            ≤ 128 chars

          • countryCountry

            Required

            ISO 3166-1 alpha-2 country code.

            ZZ is the unknown/unspecified placeholder.

            One of 250 values; see the schema.

          • localitystring

            The city or town.

            ≤ 128 chars

          • postal_codestring

            The postal or ZIP code.

            ≤ 32 chars

          • sublocalitystring

            A civil region within the locality, if any.

            ≤ 128 chars

        • business_namestring

          Required

        • currencyCurrency

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

        • phone_numberstring
        • timezonestring

          Required

          The location's IANA time zone, which its clock times are told in.

      • orderTableOrder

        The order open on a table, as the till has it. Absent when nothing is open.

        • linesarray of CalculatedOrderLine

          Required

          • idstring · uuid

            The line's own id, what a guest paying for specific items names back. Absent on a basket not yet placed.

          • namestring

            Required

            What the guest asked for, as the catalog names it now.

          • discountLineDiscount

            Why a line costs less than its catalog price, as it was applied.

            • namestring

              Required

            • amountMoney

              Required

              A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

              The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

              Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

              • amountinteger · int64

                Required

                The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

              • currencyCurrency

                Required

                ISO 4217 currency code.

                Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

                One of 182 values; see the schema.

          • modifiersarray of string

            Required

            The names of the modifiers chosen.

          • notestring
          • problemstring

            Why the line can't be ordered now. Absent when it can.

          • product_idstring · uuid

            Absent on a line rung up on a till without a product.

          • quantityQuantity

            Required

            How much of something, as a decimal string in the unit_of_measure beside it (each where there is none), as Square's quantity is: three croissants are "3", 1.4 kg of beans is "1.4". A string because a JSON number is a binary float to most parsers.

            It has at most as many decimal places as its unit's base unit holds — three in each, g and ml, six in kg and l — and a finer one is refused, never rounded. Tenvelo holds every quantity as an integer of that base unit (thousandths of an each, milligrams, microlitres; docs/decisions/0063); a client that computes with one should read the digits the same way, never through a float.

            ≤ 26 chars · pattern ^-?(0|[1-9][0-9]*)(\.[0-9]{1,6})?$

          • settledboolean

            Whether an earlier payment settled this line, so a guest paying for specific items cannot choose it again. False until a payment names the line.

          • totalMoney

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

        • ready_to_payboolean

          Required

          Whether a server has been called to take payment, and nobody has taken one since.

        • remainingMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • totalMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

      • payment_optionsPaymentOptions

        How a guest may pay at the table from their phone. Absent when nothing is open, or the business takes no card here.

        • amountMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • processorstring

          Required

          The processor the card is taken by, and so whose card field the app shows.

        • split_countinteger

          How many equal shares amount is one of. Absent when the guest isn't sharing, or the bill can't be split that many ways.

          ≥ 2

        • tip_optionsarray of TipOption

          Required

          The tips offered, lowest first and none chosen, each worked out on amount.

          • percentagePercentage

            Required

            A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

            A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

            pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

          • tipMoney

            Required

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  25. POST/v1/locations/{id}/tables/{secret}/hold

    Put a card down on a tab

    No. holdAtTableAuth no token

    Public: the table's code is the credential (docs/decisions/0113).

    Authorises the card the guest put down against the order open on the table, as a guarantee for what the tab has come to — the same hold a till places when a bar tab opens, from the guest's own phone (order-and-pay-at-table item 10). The card is the processor's token minted by the processor's own card field, never a card number, and the account's processor must be able to take a card from a phone to hold it.

    The app mints the id; a retry answers the same hold and never places a second one. A declined or unknown hold is answered as it stands, and nothing else changes.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • secretpath · string

      Required

      The secret in the table's QR code. It is the credential.

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Request body application/json · HoldAtTable

    • idstring · uuid

      Required

      Minted by the app; a retry under the same id answers the same hold.

    • cardstring

      Required

      The processor's token for the card, never a card number.

      1–256 chars

    Responses

    • 200

      The hold, as it stands immediately after the ask.

      TableHold · application/json
      • idstring · uuid

        Required

      • amountMoney

        Required

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • card_brandstring

        The card's scheme, as the processor reported it — Visa, Mastercard.

      • card_last4string

        The last four digits of the card, as the processor reported them. Never the PAN.

      • statusstring · enum

        Required

        pendingunknownhelddeclinedfailedsettledvoidedexpired

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 415

      The request Content-Type is not supported. This API accepts application/json on all mutations.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  26. POST/v1/locations/{id}/tables/{secret}/order

    Order at a table

    No. orderAtTableAuth no token

    Adds what the guest chose to the order open on the table, priced against the catalog as it stands. Where nothing is open, the guest's order opens one if the location lets a guest do that, and is a 404 (no-open-order) if not. Where the location has a server accept each guest order, it reaches the kitchen once they do.

    The app mints the id when the guest starts choosing, so a retry after a lost answer adds the lines once, while ordering the same again later is another order.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • secretpath · string

      Required

      The secret in the table's QR code. It is the credential.

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Request body application/json · OrderAtTable

    • idstring · uuid

      Required

      Minted by the app when the guest starts choosing, so a retry adds the lines once.

    • linesarray of BasketLine

      Required

      ≥ 1 items · ≤ 50 items

      • modifier_idsarray of string · uuid

        ≤ 50 items

      • notestring

        ≤ 200 chars

      • product_idstring · uuid

        Required

      • quantityQuantity

        Required

        How much of something, as a decimal string in the unit_of_measure beside it (each where there is none), as Square's quantity is: three croissants are "3", 1.4 kg of beans is "1.4". A string because a JSON number is a binary float to most parsers.

        It has at most as many decimal places as its unit's base unit holds — three in each, g and ml, six in kg and l — and a finer one is refused, never rounded. Tenvelo holds every quantity as an integer of that base unit (thousandths of an each, milligrams, microlitres; docs/decisions/0063); a client that computes with one should read the digits the same way, never through a float.

        ≤ 26 chars · pattern ^-?(0|[1-9][0-9]*)(\.[0-9]{1,6})?$

      • variant_idstring · uuid

    Responses

    • 200

      The table, with the lines added.

      TableBill · application/json
      • namestring

        Required

        The table's name, as the room knows it.

      • can_orderboolean

        Required

        Whether the guest may order at the table now. Where nothing is open, only if the location lets a guest's order open the table.

      • card_holdTableHold

        The card a guest put down at a table, as the bill page shows it: an authorisation on the open order, never a capture, and never the card's number — the brand and the last four are the processor's word, as a payment shows them.

        • idstring · uuid

          Required

        • amountMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • card_brandstring

          The card's scheme, as the processor reported it — Visa, Mastercard.

        • card_last4string

          The last four digits of the card, as the processor reported them. Never the PAN.

        • statusstring · enum

          Required

          pendingunknownhelddeclinedfailedsettledvoidedexpired

      • locationOrderLocation

        Required

        The location an order is collected from.

        • namestring

          Required

        • addressAddress

          A postal address.

          The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

          The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

          • address_line_1string

            Required

            First line of the address — street number, street name, building name.

            ≤ 255 chars

          • address_line_2string

            Second line of the address, if any.

            ≤ 255 chars

          • address_line_3string

            Third line of the address, if any.

            ≤ 255 chars

          • administrative_district_level_1string

            A civil entity within the country. The state in the US; the county in the UK.

            ≤ 128 chars

          • administrative_district_level_2string

            A civil entity within administrative_district_level_1.

            ≤ 128 chars

          • countryCountry

            Required

            ISO 3166-1 alpha-2 country code.

            ZZ is the unknown/unspecified placeholder.

            One of 250 values; see the schema.

          • localitystring

            The city or town.

            ≤ 128 chars

          • postal_codestring

            The postal or ZIP code.

            ≤ 32 chars

          • sublocalitystring

            A civil region within the locality, if any.

            ≤ 128 chars

        • business_namestring

          Required

        • currencyCurrency

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

        • phone_numberstring
        • timezonestring

          Required

          The location's IANA time zone, which its clock times are told in.

      • orderTableOrder

        The order open on a table, as the till has it. Absent when nothing is open.

        • linesarray of CalculatedOrderLine

          Required

          • idstring · uuid

            The line's own id, what a guest paying for specific items names back. Absent on a basket not yet placed.

          • namestring

            Required

            What the guest asked for, as the catalog names it now.

          • discountLineDiscount

            Why a line costs less than its catalog price, as it was applied.

            • namestring

              Required

            • amountMoney

              Required

              A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

              The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

              Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

              • amountinteger · int64

                Required

                The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

              • currencyCurrency

                Required

                ISO 4217 currency code.

                Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

                One of 182 values; see the schema.

          • modifiersarray of string

            Required

            The names of the modifiers chosen.

          • notestring
          • problemstring

            Why the line can't be ordered now. Absent when it can.

          • product_idstring · uuid

            Absent on a line rung up on a till without a product.

          • quantityQuantity

            Required

            How much of something, as a decimal string in the unit_of_measure beside it (each where there is none), as Square's quantity is: three croissants are "3", 1.4 kg of beans is "1.4". A string because a JSON number is a binary float to most parsers.

            It has at most as many decimal places as its unit's base unit holds — three in each, g and ml, six in kg and l — and a finer one is refused, never rounded. Tenvelo holds every quantity as an integer of that base unit (thousandths of an each, milligrams, microlitres; docs/decisions/0063); a client that computes with one should read the digits the same way, never through a float.

            ≤ 26 chars · pattern ^-?(0|[1-9][0-9]*)(\.[0-9]{1,6})?$

          • settledboolean

            Whether an earlier payment settled this line, so a guest paying for specific items cannot choose it again. False until a payment names the line.

          • totalMoney

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

        • ready_to_payboolean

          Required

          Whether a server has been called to take payment, and nobody has taken one since.

        • remainingMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • totalMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

      • payment_optionsPaymentOptions

        How a guest may pay at the table from their phone. Absent when nothing is open, or the business takes no card here.

        • amountMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • processorstring

          Required

          The processor the card is taken by, and so whose card field the app shows.

        • split_countinteger

          How many equal shares amount is one of. Absent when the guest isn't sharing, or the bill can't be split that many ways.

          ≥ 2

        • tip_optionsarray of TipOption

          Required

          The tips offered, lowest first and none chosen, each worked out on amount.

          • percentagePercentage

            Required

            A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

            A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

            pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

          • tipMoney

            Required

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 415

      The request Content-Type is not supported. This API accepts application/json on all mutations.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  27. POST/v1/locations/{id}/tables/{secret}/pay

    Pay at a table

    No. payAtTableAuth no token

    Charges the guest's card against the order open on the table, through the processor the business's card-not-present account names. The card is the processor's token for it, minted by the processor's own card field, never a card number.

    Without an amount it pays all that remains. A tip is either typed, as tip, or one of the offered percentages, as tip_percentage, never both; a percentage is charged only against what it was offered on, all that remains or one equal share of split_count, so the card is charged the tip the guest was shown.

    The app mints the id; a retry answers the same charge and never takes the card twice. A declined or unknown charge leaves the order open. Rate limited per client address.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • secretpath · string

      Required

      The secret in the table's QR code. It is the credential.

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Request body application/json · PayAtTable

    • idstring · uuid

      Required

      Minted by the app when the guest starts paying; a retry names the same charge.

    • amountMoney

      A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

      The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

      Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

      • amountinteger · int64

        Required

        The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

      • currencyCurrency

        Required

        ISO 4217 currency code.

        Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

        One of 182 values; see the schema.

    • cardstring

      The processor's token for the card, never a card number. Exactly one of card and hold_id names what is taken.

      1–256 chars

    • hold_idstring · uuid

      Settle the card the guest already put down on this tab instead of charging a new one: the guarantee is captured, never a second card. Not with card; the amount before any tip is what the guest is paying with it, and the held card may only settle the tab it was put down on.

    • line_item_idsarray of string · uuid

      The whole lines the guest is paying for, when they chose specific items: the server charges their sum and records each line as settled by this tender, so a reopened tab re-derives the split from the record (order-and-pay item 11). Not with amount or split_count; the guest types the tip when paying for chosen items. A line settled by an earlier tender, or not on this order, is refused.

      ≤ 100 items

    • split_countinteger

      The split_count the options were offered for, when the guest is paying one equal share.

      2–20

    • tipMoney

      A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

      The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

      Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

      • amountinteger · int64

        Required

        The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

      • currencyCurrency

        Required

        ISO 4217 currency code.

        Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

        One of 182 values; see the schema.

    • tip_percentagePercentage

      A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

      A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

      pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

    Responses

    • 200

      The charge, and what came of it.

      TablePayment · application/json
      • idstring · uuid

        Required

      • amountMoney

        Required

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • statusstring · enum

        Required

        pendingapproveddeclinedunknown

      • tipMoney

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 415

      The request Content-Type is not supported. This API accepts application/json on all mutations.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  28. POST/v1/locations/{id}/waitlist/join

    Join the waitlist

    No. joinLocationWaitlistAuth no token

    Public: what anyone may do at a location (docs/decisions/0113).

    Puts a party on the venue's queue from its own page, at the room named in the path. A venue that does not take the waitlist online (online_booking.waitlist_enabled) is refused with a 422, as is a party larger than what the room takes online; a party the customer joined again under the same id is the entry it already made. The host sees the entry on the change feed as it is made, and the waitlist's join text goes to the phone recorded here, when one is given. Rate limited per client address.

    Parameters

    • idpath · string · uuid

      Required

      The location, by its id.

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Request body application/json · WaitlistEntryCreate

    • idstring · uuid

      Minted by the caller, so a party added again after a lost response is answered with the entry it already made rather than queued twice. The server mints one when absent.

    • namestring

      Required

      The name the party is taken under.

    • customer_idstring · uuid

      The directory guest this party is, if one was matched.

    • location_idstring · uuid

      The room the party is waiting at. A till may name only its own.

    • notestring

      Anything the front of house needs to remember for the visit.

    • party_sizeinteger

      Required

      How many people are in the party.

      ≥ 1

    • phonestring

      A contact for the party, so the host can call them back.

    Responses

    • 201

      The party is on the queue.

      WaitlistEntry · application/json
      • idstring · uuid

        Required

        The queue entry's own id, minted when the party was taken.

      • namestring

        Required

        The name the party was taken under.

      • created_atstring · date-time

        RequiredRead only

      • customer_idstring · uuid

        The directory guest this party is, if one was matched.

      • location_idstring · uuid

        Required

        The room the party is waiting at.

      • notestring

        Anything the front of house needs to remember for the visit.

      • party_sizeinteger

        Required

        How many people are in the party.

        ≥ 1

      • phonestring

        A contact for the party, so the host can call them back when a table frees.

      • statusstring · enum

        Required

        waiting — the party is in the queue.

        seated — the party has been shown to its table; its tab is open.

        left — the party gave up or was not seated.

        waitingseatedleft

      • updated_atstring · date-time

        Read only

      • versioninteger · int64

        Required

        The version the caller last saw, sent back as If-Match when changing it.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 404

      No such resource, or none visible to this caller.

      Also returned instead of 403 where acknowledging existence would itself leak information — so a 404 does not prove the id is unused globally, only that it is not yours.

    • 409

      The request conflicts with current state — a uniqueness constraint, or an attempt to mutate an order that is already completed or voided.

      Unlike 412, re-reading and retrying unchanged will not resolve it; the request itself has to change.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 415

      The request Content-Type is not supported. This API accepts application/json on all mutations.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.

  29. POST/v1/me/erase

    Erase the account

    No. eraseAccountAuth bearer

    The account erases itself and everything its sign-in holds (docs/decisions/0115 §8, 0117 §4): the issuer's record of who the subject is, the share agreements it made with each merchant, the share moments still waiting, and every merchant's guest record carrying its merchant-side subject — erased as the merchant's own erase erases a guest. The account's order facts fall with the guest records: its history and rewards read only where a share exists. Idempotent: asking again erases nothing. The person's sign-ins are ended; their identity account (an office sign-in, a staff or owner role) is not.

    The bearer is the account's — the guest app's token from the issuer, and nothing else.

    Responses

    • 204

      The account is erased.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

  30. GET/v1/me/orders

    The account's own orders

    No. listAccountOrdersAuth bearer

    The orders an account placed, across every venue, newest first (docs/decisions/0117 §4), for the app's history and "order again". The bearer is the account's: the guest app's token from the issuer, and nothing else — a person or agent token is not an account, and a guest with no token is anonymous and is answered 401.

    An order placed with only an emailed code at a venue is not the account's, so it is not here. Erasing the account erases every row it names.

    Parameters

    • cursorquery · string

      Opaque cursor from a previous page's next_cursor. Omit to start from the beginning.

      Pass it back exactly as received. It is base64 and its structure is not part of this contract — decoding it, or constructing one by hand, will break without notice.

    • limitquery · integer · int32

      Maximum items to return. The server may return fewer, so always drive the loop from has_more rather than from the size of the page you got back.

    Responses

    • 200

      A page of the account's orders.

      AccountOrdersPage · application/json
      • has_moreboolean

        Required

      • itemsarray of AccountOrder

        Required

        • linesarray of AccountOrderLine

          Required

          • namestring

            Required

            What the order called it.

            ≤ 200 chars

          • modifier_idsarray of string · uuid

            ≤ 50 items

          • notestring

            ≤ 200 chars

          • product_idstring · uuid

            Required

            The product as the venue sells it now. What it no longer sells is left out.

          • quantityQuantity

            Required

            How much of something, as a decimal string in the unit_of_measure beside it (each where there is none), as Square's quantity is: three croissants are "3", 1.4 kg of beans is "1.4". A string because a JSON number is a binary float to most parsers.

            It has at most as many decimal places as its unit's base unit holds — three in each, g and ml, six in kg and l — and a finer one is refused, never rounded. Tenvelo holds every quantity as an integer of that base unit (thousandths of an each, milligrams, microlitres; docs/decisions/0063); a client that computes with one should read the digits the same way, never through a float.

            ≤ 26 chars · pattern ^-?(0|[1-9][0-9]*)(\.[0-9]{1,6})?$

          • variant_idstring · uuid

            The variant chosen, when the product has sizes.

        • listingMarketplaceListing

          Required

          A location as the marketplace shows it to a guest (docs/decisions/0115): where it is, when it trades, how far away it is, and the ways it takes orders. Ordering happens on the location's own page, at page_url.

          • namestring

            Required

            The location's name.

          • accepting_ordersboolean

            Required

            Whether the ordering page takes an order now. False while it is paused or off.

          • addressAddress

            Required

            A postal address.

            The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

            The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

            • address_line_1string

              Required

              First line of the address — street number, street name, building name.

              ≤ 255 chars

            • address_line_2string

              Second line of the address, if any.

              ≤ 255 chars

            • address_line_3string

              Third line of the address, if any.

              ≤ 255 chars

            • administrative_district_level_1string

              A civil entity within the country. The state in the US; the county in the UK.

              ≤ 128 chars

            • administrative_district_level_2string

              A civil entity within administrative_district_level_1.

              ≤ 128 chars

            • countryCountry

              Required

              ISO 3166-1 alpha-2 country code.

              ZZ is the unknown/unspecified placeholder.

              One of 250 values; see the schema.

            • localitystring

              The city or town.

              ≤ 128 chars

            • postal_codestring

              The postal or ZIP code.

              ≤ 32 chars

            • sublocalitystring

              A civil region within the locality, if any.

              ≤ 128 chars

          • business_hoursarray of DaypartWindow

            Required

            The hours the location trades, in its own timezone.

            ≤ 8 items

            • daysarray of integer

              The weekdays this window opens on, 1 (Monday) through 7 (Sunday). An empty or absent list is every day.

              ≤ 7 items

            • end_minuteinteger

              Required

              1–1440

            • start_minuteinteger

              Required

              0–1439

          • business_namestring

            Required

            The business the location belongs to, by its trading name where it has one.

          • collectionboolean

            Required

            Whether a guest can order online to collect.

          • coordinatesCoordinates

            Required

            A point on the WGS 84 ellipsoid, in decimal degrees. Square's location coordinates.

            • latitudenumber · double

              Required

              -90–90

            • longitudenumber · double

              Required

              -180–180

          • descriptionstring

            Required

            What the location says about itself. Empty when it says nothing.

            ≤ 280 chars

          • distance_metersinteger · int64

            Required

            How far the location is from the point asked about, along the great circle, in meters.

            ≥ 0

          • location_idstring · uuid

            Required

          • page_urlstring · uri

            RequiredNullable

            The location's ordering page, or null when it takes orders only at its tables.

          • prep_time_minutesinteger · int32

            Required

            What the location quotes for collection, in minutes.

            ≥ 0

          • table_orderingboolean

            Required

            Whether a guest at a table can scan its code to order and pay.

          • timezoneTimezone

            Required

            IANA time zone identifier.

            Used to resolve a location's business day for reporting and settlement.

            One of 348 values; see the schema.

        • order_idstring · uuid

          Required

        • received_atstring · date-time

          Required

        • statestring · enum

          Required

          opencompletedcanceledvoided

        • totalMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

      • next_cursorstring

        Nullable

        ≤ 512 chars

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

  31. GET/v1/me/push-token

    The phone the account registered to be pushed

    No. getGuestPushTokenAuth bearer

    The account's one registered phone and its switch for the push telling them an online order is ready (design/marketplace, t-you, Notifications). Nothing to read where nothing is registered — the answer then is 404, which the app reads as "no phone yet".

    The bearer is the account's — the guest app's token from the issuer, and nothing else.

    Responses

    • 200

      The account's registered phone.

      GuestPushToken · application/json
      • platformPushPlatform

        Required

        The push service a phone's token is for: Apple's (apns, a device token) or Google's Firebase Cloud Messaging (fcm, a registration token).

        apnsfcm

      • tokenstring

        Required

        The push service's token for the phone.

      • versionVersion

        RequiredRead only

        Optimistic concurrency version, raised by the server on every write. A version is never lower than one already returned for the resource, though it may rise by more than one.

        Returned in the ETag response header as well as in the body. Send it back in If-Match on an update and the write is rejected with 412 if anyone else has written since — which is what stops two tills silently overwriting each other's edit to the same product when both come back online at once.

        ≥ 1

      • wants_readyboolean

        Required

        Whether the account wants the push when an online order is ready.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

  32. POST/v1/me/push-token

    Register the phone the account is pushed on

    No. createGuestPushTokenAuth bearer

    Records the phone the account's app holds with its push service, and the account's switch for the push telling them an online order is ready (design/marketplace, t-you, Notifications). One registered phone per account: asking again with a newer token replaces it, which is how the platform's token rotates, and asking again with the same one is the registration already there — an idempotent act, never a second row.

    The bearer is the account's — the guest app's token from the issuer, and nothing else.

    Request body application/json · GuestPushTokenRequest

    • platformPushPlatform

      Required

      The push service a phone's token is for: Apple's (apns, a device token) or Google's Firebase Cloud Messaging (fcm, a registration token).

      apnsfcm

    • tokenstring

      Required

      The push service's token for the phone, as the app received it.

      ≥ 1 chars

    • wants_readyboolean

      Required

      Whether the account wants the push when an online order is ready.

    Responses

    • 204

      The phone is registered.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

  33. DELETE/v1/me/push-token

    Forget the phone the account registered

    No. deleteGuestPushTokenAuth bearer

    Forgets the phone the account registered (design/marketplace, t-you, Notifications): no push is asked for it again. Idempotent: forgetting one that is not there is the same done act — the account keeps no registration and the answer is the same.

    The bearer is the account's — the guest app's token from the issuer, and nothing else.

    Parameters

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Responses

    • 204

      The phone is forgotten.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

  34. GET/v1/me/rewards

    The account's rewards

    No. listAccountRewardsAuth bearer

    Each business's loyalty balance the account holds, side by side (docs/decisions/0117 §5): one row per business, nothing pooled with another's. The bearer is the account's — the guest app's token from the issuer, and nothing else. A balance is read only where the account shared with the business, because only then does its guest record carry the account's subject; a business is in the list only when it runs a programme the account is in. The app opens the business's page with page_url.

    Parameters

    • cursorquery · string

      Opaque cursor from a previous page's next_cursor. Omit to start from the beginning.

      Pass it back exactly as received. It is base64 and its structure is not part of this contract — decoding it, or constructing one by hand, will break without notice.

    • limitquery · integer · int32

      Maximum items to return. The server may return fewer, so always drive the loop from has_more rather than from the size of the page you got back.

    Responses

    • 200

      A page of the account's rewards.

      AccountRewardsPage · application/json
      • has_moreboolean

        Required

      • itemsarray of AccountReward

        Required

        • balanceinteger · int64

          Required

          Points the guest holds with this business.

        • business_namestring

          Required

          The business the balance is with.

        • location_idsarray of string · uuid

          Required

          The business's online locations, so the app matches the venue the guest is looking at.

        • page_urlstring · uri

          Nullable

          The business's ordering page, for opening it.

        • tierstring

          Nullable

          The tier the guest is on, when the programme has tiers.

        • worthMoney

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

      • next_cursorstring

        Nullable

        ≤ 512 chars

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

  35. GET/v1/me/shares

    The venues the account shares with

    No. listAccountSharesAuth bearer

    Every business the account has agreed to share its details with, one row per business (docs/decisions/0115 §6, 0117 §2): when each agreement was made and which details the business was granted. Pairwise identity is invisible unless a screen shows it, and this is that screen's reading: each business keeps its own record of the person, and none can see what another holds. Nothing is read where no share exists.

    The bearer is the account's — the guest app's token from the issuer, and nothing else.

    Parameters

    • cursorquery · string

      Opaque cursor from a previous page's next_cursor. Omit to start from the beginning.

      Pass it back exactly as received. It is base64 and its structure is not part of this contract — decoding it, or constructing one by hand, will break without notice.

    • limitquery · integer · int32

      Maximum items to return. The server may return fewer, so always drive the loop from has_more rather than from the size of the page you got back.

    Responses

    • 200

      A page of the account's shares.

      AccountSharesPage · application/json
      • has_moreboolean

        Required

      • itemsarray of AccountShare

        Required

        • business_namestring

          Required

          The business as its own page says it (its trading name, else its business name).

        • heldobject

          Required

          Which of the person's details the business may keep. A name is always required to take an order; email and phone are each the person's own choice, and each says what it is for when it is asked.

          • nameboolean

            Required

          • emailboolean

            Required

          • phoneboolean

            Required

        • merchant_idstring · uuid

          Required

          The business the account shared with.

        • shared_sincestring · date-time

          Required

          When the agreement was made, which is also when the business's record began.

      • next_cursorstring

        Nullable

        ≤ 512 chars

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

  36. POST/v1/me/shares/{merchant_id}/revoke

    Stop sharing with a venue

    No. revokeAccountShareAuth bearer

    Withdraws the agreement with one business (docs/decisions/0115 §6, 0117 §4): the business's record of the person is erased, as the merchant's own erase of a guest erases it, and the agreement that allowed it is withdrawn. The fact of having shared is kept — a revoke keeps the record — so the moment is not re-asked until the person orders there again. The account's own history and rewards fall with the guest record: they read only where a share exists.

    The bearer is the account's — the guest app's token from the issuer, and nothing else. Only a business the account actually shared with is touched; a business already erased, or one that never shared, is left alone and the request still answers its end.

    Parameters

    • merchant_idpath · string · uuid

      Required

      The business whose share with the account is being ended.

    • Idempotency-Keyheader · string

      Required

      A client-generated key making this request safe to retry.

      Required on every mutation that creates a resource or moves money. A till on bad wifi cannot tell a lost response from a lost request; without a key its only options are to risk a duplicate sale or to drop a real one. With a key it retries freely: the first request to arrive is processed, and every replay returns that same stored response.

      Rules:

      • Mint the key once, when the operation is first queued, and reuse it for every retry. A fresh key per attempt defeats the mechanism entirely.
      • Keys are scoped per merchant and per operation, and are retained for 30 days — long enough that a till switched off mid-sync can retry with the same key however long it stayed on the shelf.
      • Replaying a key with a different request body is a client bug and is rejected with 422, rather than silently returning the first result — quietly serving the old response would hide a real inconsistency in the caller.

      A UUIDv7 or ULID is a good choice.

    Responses

    • 204

      The share with the business is ended.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

  37. POST/v1/partner-orders

    Record a middleware partner's order

    No. createPartnerOrderAuth ordering:write

    Records an order a middleware partner (Deliverect or another) reported — a delivery platform's sale normalized to our vocabulary (online-ordering.md item 6). The server resolves each line to the merchant's product by id or by the SKU the catalogue carries, records the order at the partner's own prices — the platform charged the guest, so the price it reports is the fact, never the catalogue's — and the order arrives open and asked-for, for the venue to take on or turn down like any channel's.

    The order's channel is integration and its source is the calling integration client, so a later word from the platform about the order matches by external_reference.

    Request body application/json · PartnerOrderWrite

    • idstring · uuid

      Required

      The order's id, minted by the caller so a retry names the same order.

    • customer_emailstring · email

      How to reach the customer, when the platform has it.

    • customer_namestring

      Who the order is for, as the platform carried it.

      ≤ 100 chars

    • customer_phonestring

      How to reach the customer, when the platform has it.

      ≤ 32 chars

    • delivery_addressAddress

      A postal address.

      The address_line_* fields carry the most specific part of the address — street number, street name, building name. Less specific detail belongs in locality, administrative_district_level_* and country.

      The administrative_district_level_* fields are deliberately generic because their meaning is country-dependent: in the US level 1 is the state and level 2 the county; in the UK level 1 is the county.

      • address_line_1string

        Required

        First line of the address — street number, street name, building name.

        ≤ 255 chars

      • address_line_2string

        Second line of the address, if any.

        ≤ 255 chars

      • address_line_3string

        Third line of the address, if any.

        ≤ 255 chars

      • administrative_district_level_1string

        A civil entity within the country. The state in the US; the county in the UK.

        ≤ 128 chars

      • administrative_district_level_2string

        A civil entity within administrative_district_level_1.

        ≤ 128 chars

      • countryCountry

        Required

        ISO 3166-1 alpha-2 country code.

        ZZ is the unknown/unspecified placeholder.

        One of 250 values; see the schema.

      • localitystring

        The city or town.

        ≤ 128 chars

      • postal_codestring

        The postal or ZIP code.

        ≤ 32 chars

      • sublocalitystring

        A civil region within the locality, if any.

        ≤ 128 chars

    • external_referencestring

      Required

      The platform's own order id, which the venue matches what the platform later says about the order against.

      ≥ 1 chars

    • fulfillment_typestring · enum

      Required

      How the order leaves the building.

      pickupdelivery

    • linesarray of PartnerOrderLine

      Required

      ≥ 1 items · ≤ 200 items

      • notestring

        A per-line instruction ("no onions").

        ≤ 200 chars

      • product_idstring · uuid

        The merchant's product, when the partner carries our id.

      • quantityQuantity

        Required

        How much of something, as a decimal string in the unit_of_measure beside it (each where there is none), as Square's quantity is: three croissants are "3", 1.4 kg of beans is "1.4". A string because a JSON number is a binary float to most parsers.

        It has at most as many decimal places as its unit's base unit holds — three in each, g and ml, six in kg and l — and a finer one is refused, never rounded. Tenvelo holds every quantity as an integer of that base unit (thousandths of an each, milligrams, microlitres; docs/decisions/0063); a client that computes with one should read the digits the same way, never through a float.

        ≤ 26 chars · pattern ^-?(0|[1-9][0-9]*)(\.[0-9]{1,6})?$

      • skustring

        The merchant's SKU for the product (or its variant), as the catalogue carries it.

      • unit_priceMoney

        Required

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • variant_idstring · uuid

        The sellable unit when the product is sold as variants.

      • variant_skustring

        The variant's own SKU when the partner carries it.

    • location_idstring · uuid

      Required

      The site the order is for, within the integration's merchant.

    • notestring

      A platform-level instruction ("ring the doorbell twice").

      ≤ 500 chars

    • pickup_atstring · date-time

      The collection or delivery time the venue quoted. Absent for as soon as it can be ready.

    Responses

    • 201

      The order was recorded; a person at the venue will take it on.

      Order · application/json
      • idstring · uuid

        Required

        UUIDv7, minted by the device before the sale is synced. This is what makes an offline order idempotent: replaying it targets the same id, so a retry over flaky wifi cannot create a duplicate sale.

      • namestring

        Nullable

        Whose sale it is, while it is open: a customer's name, whatever the shop shouts across the bar. Null is a walk-in being served at a counter right now.

        ≤ 128 chars

      • acceptancestring · enum

        Read only

        Where an asked-for order stands with the venue that must make it, beside its lifecycle: state keeps its four values. A till's own order is accepted as it is created; a channel's — the ordering page, an integration — is pending until a person or a rule takes it on, or it is rejected with a reason. Set by the server, never from the body: acceptance is a fact (engineering, recording what happened, section 12), not a field a client sets.

        pendingacceptedrejected

      • age_confirmedboolean

        Whether a sale carrying an age-restricted line recorded that the till confirmed the guest's age before it completed. False both for a sale with no age-restricted line and for one that needed the check and did not record it — the reports compare it with age_minimum to flag the second.

        default false

      • age_minimuminteger · int32

        The oldest buyer the sale's age-restricted lines allowed, as the till recorded it: the highest minimum_age among them, 0 when the sale carried none. A completed sale with age_minimum above 0 and age_confirmed false is a counter law miss.

        ≥ 0 · default 0

      • business_datestring · date

        Read only

        The trading day the sale belongs to, in its location's own reckoning: its time zone and the hour its day starts. Set by the server when the sale completes, from when the till says it happened, so a sale rung at 1am on a late night books to the night before. Absent on an order that has not completed.

      • channelstring · enum

        Read only

        Where the order came from, set by the server from the caller and never accepted from the body: pos is a till, table a table-side device, online an online storefront, integration a third-party integration. A till cannot attribute a sale to another channel. What the channel is tells an integration whose order arrived from where, which an order_type cannot.

        postableonlineintegration

      • channel_costMoney

        What the channel took from the order, at the stated cost in force on the order's business date (online-ordering item 18). Present only for an online order whose channel states a cost, and derived on read from the stated rates and the order's total — never stored, so it can never drift from them.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • client_created_atstring · date-time

        Required

        When the device believes the sale happened. Trusted for display — it is what a receipt shows and what staff recognise — but never for ordering or for resolving conflicts, because till clocks drift. Compare with received_at to measure how long a device was offline.

      • closed_atstring · date-time

        Nullable

        When the order left open — was completed. A void does not change it; voided_at is when the sale was voided.

      • coversinteger · int32

        RequiredRead only

        How many people the party is, as counted at seating on the created fact; zero where nobody counted them. The covers-per-labour-hour and average-spend-per-cover figures are divided by it, so a tab opened without a count adds no covers rather than one.

        0–1000 · default 0

      • created_atTimestamp

        RequiredRead only

        Server-assigned RFC 3339 timestamp, always UTC.

        Server-assigned because device clocks drift and cannot be trusted for ordering — a till that has been powered off for a week may come back with a clock hours out. Where the device's own view of time matters it is carried separately in client_created_at.

      • currencyCurrency

        Required

        ISO 4217 currency code.

        Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

        One of 182 values; see the schema.

      • customerCustomerLoyalty

        This order's guest as a till may see them: name, loyalty balance and what it can afford. Carried on the order and its change-feed entry so a till that picks a tab up on another device shows the badge and offers a redemption without a second call. Absent for a walk-in and for a guest since erased or merged; customer_id remains the record. Additive: a client that predates it simply omits it.

        • idstring · uuid

          Required

        • namestring

          Required

        • loyalty_pointsinteger · int64

          The guest's current loyalty balance, earned minus redeemed.

        • rewardsarray of Reward

          The reward catalogue entries this guest can afford, so a till can offer them at redemption. Server-computed from the balance; a guest not enrolled sees none.

          • idstring · uuid

            Required

          • namestring

            Required

            What the reward is called to the guest and on the receipt.

          • cost_pointsinteger · int64

            Required

            What redeeming it costs, in points.

          • discount_idstring · uuid

            Required

            The discount definition the reward is backed by.

        • tagsstring

          The guest's labels, carried so a counter can offer them; still no contact details and no note.

        • tierLoyaltyTierStatus

          A guest's standing in a loyalty programme's ladder at one moment (loyalty item 16): the tier they are on, the next tier above, and how much more they need to reach it.

          • currentLoyaltyTier

            One named level in a loyalty programme's ladder (loyalty item 16). Exactly one of threshold_spend and threshold_visits is set; window_days is the rolling window over which the qualifying spend or visits are counted, and earn_rate_percentage is the multiplier on the programme's base earn rate (10000 is 1x).

            • idstring · uuid

              Required

            • namestring

              Required

            • earn_rate_percentageRelativePercentage

              A percentage that may be negative or above 100, such as a change on a period before or a multiplier, in a decimal string with at most four decimal places: a fall of an eighth is "-12.5", and one and a half times is "150". Read and computed as a Percentage is, in parts per million.

              pattern ^-?(0|[1-9][0-9]{0,8})(\.[0-9]{1,4})?$

            • threshold_spendMoney

              A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

              The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

              Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

              • amountinteger · int64

                Required

                The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

              • currencyCurrency

                Required

                ISO 4217 currency code.

                Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

                One of 182 values; see the schema.

            • threshold_visitsinteger · int64

              The number of completed linked orders that reaches the tier.

            • window_daysinteger · int32
          • nextLoyaltyTier

            One named level in a loyalty programme's ladder (loyalty item 16). Exactly one of threshold_spend and threshold_visits is set; window_days is the rolling window over which the qualifying spend or visits are counted, and earn_rate_percentage is the multiplier on the programme's base earn rate (10000 is 1x).

            • idstring · uuid

              Required

            • namestring

              Required

            • earn_rate_percentageRelativePercentage

              A percentage that may be negative or above 100, such as a change on a period before or a multiplier, in a decimal string with at most four decimal places: a fall of an eighth is "-12.5", and one and a half times is "150". Read and computed as a Percentage is, in parts per million.

              pattern ^-?(0|[1-9][0-9]{0,8})(\.[0-9]{1,4})?$

            • threshold_spendMoney

              A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

              The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

              Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

              • amountinteger · int64

                Required

                The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

              • currencyCurrency

                Required

                ISO 4217 currency code.

                Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

                One of 182 values; see the schema.

            • threshold_visitsinteger · int64

              The number of completed linked orders that reaches the tier.

            • window_daysinteger · int32
          • spend_neededMoney

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

          • visits_neededinteger · int64

            The visits still needed to reach next, when next is reached by visits.

        • versioninteger · int64

          Required

          The guest record's version, for the optimistic write a picker makes; it may be stale by the time the write lands, and the batch then refuses.

      • customer_idstring · uuid

        Nullable

        The guest this sale is recorded against, if any. Null for a walk-in.

      • delivery_addressAddress

        Where a delivery order goes, as the writer stated it, when the order's fulfillment is delivery.

        • address_line_1string

          Required

          First line of the address — street number, street name, building name.

          ≤ 255 chars

        • address_line_2string

          Second line of the address, if any.

          ≤ 255 chars

        • address_line_3string

          Third line of the address, if any.

          ≤ 255 chars

        • administrative_district_level_1string

          A civil entity within the country. The state in the US; the county in the UK.

          ≤ 128 chars

        • administrative_district_level_2string

          A civil entity within administrative_district_level_1.

          ≤ 128 chars

        • countryCountry

          Required

          ISO 3166-1 alpha-2 country code.

          ZZ is the unknown/unspecified placeholder.

          One of 250 values; see the schema.

        • localitystring

          The city or town.

          ≤ 128 chars

        • postal_codestring

          The postal or ZIP code.

          ≤ 32 chars

        • sublocalitystring

          A civil region within the locality, if any.

          ≤ 128 chars

      • delivery_feeMoney

        Nullable

        The venue's delivery charge on a delivered order (online-ordering: a shop may charge for delivery), snapshotted from its settings at write, or null when none. Part of the total; never folded into goods or their tax.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • device_idstring · uuid

        The till that last wrote the order. On an open order this is not ownership — any device at the location may pick a tab up, which is the entire point.

      • device_seqinteger · int64

        Nullable

        The device's monotonic sequence for this write, if the till recorded one.

      • documentOrderDocument

        The fiscal document a completed order is recorded as, in the per-till series 0016 builds. Every sales document a till issues belongs to a series it was issued at enrolment, and the number is a gap-free counter in that series, incremented in the same transaction that completes the order. Printed on the receipt and sent with the order; the server stores it and refuses a duplicate (series, number).

        This is the number a market's fiscal rules are about — the correlative number within a series. It is not the order's reference, which stays the short per-day call number for staff to find a sale.

        • kindstring · enum

          Required

          What the document is. invoice is the ordinary receipt — the simplified invoice most markets call a receipt. A full invoice and a rectifying document will be separate kinds, each in its own series.

          invoice

          default invoice

        • numberinteger · int64

          Required

          The gap-free sequence number within the series, starting at 1. Never reused: a void keeps its number, and a correction is a new document in a rectifying series.

          ≥ 1

        • seriesstring

          Required

          The series this document belongs to: a short code issued to one till at enrolment (e.g. B1-T3), one per device and kind of document. The ordinary receipt is in the invoice series.

          ≤ 32 chars

      • drawer_session_idstring · uuid

        Nullable

        The drawer session this sale was rung in, if any. Null otherwise.

      • email_receiptboolean

        Whether the customer on this order asked for its receipt to be emailed. The address is always the customer record's — never typed onto the order, which is a financial record — and only honoured when the guest has consented. Additive, so a till that predates it simply omits it.

        default false

      • external_referencestring

        Read only

        The writer's own reference for the order, when one was given.

        ≤ 128 chars

      • flagsarray of OrderFlagKind

        Read only

        The kinds of the flags still open on the order, which the books could not settle; absent when none is. Read beside the order as refunded is, and left out of the change feed.

      • fulfillment_statusstring · enum

        Read only

        Where an asked-for order has got to, for the guest and the venue: received until the venue takes it on, preparing once accepted, ready once said to be, collected once completed, or rejected or canceled. Derived from acceptance, ready_at and state when the order is read, never stored, so a client shows it rather than working it out again. Toast's fulfillmentStatus. Absent on a till's own sale, which is not asked for.

        receivedpreparingreadycollectedrejectedcanceled

      • fulfillment_typestring · enum

        Required

        How the sale leaves the building, as the glossary names it and a tax rule is keyed by (docs/decisions/0014): on_premises is what the law calls eat-in, pickup is takeaway and delivery is delivery — Square's fulfillment type, Toast's dining option. A sale that does not say is on premises.

        on_premisespickupdelivery

      • line_itemsarray of OrderLineItem

        Required

        What was sold. A completed order has at least one line; an open order may be empty for a moment, while the tab it is has just been started.

        • idstring · uuid

          Required

          UUIDv7, minted by the device.

        • namestring

          Required

          Product name as sold. Snapshot; never re-read from the product.

          1–255 chars

        • approved_by_memberMemberSnapshot

          Nullable

          The manager or owner who authorised a staff member's discount or comp above the merchant's discount_approval_threshold_minor/discount_approval_threshold_percentage or a comp when comp_requires_manager is set, as they were then; null when no approval was needed.

          • idstring · uuid

            Required

            The roster's id, checked against the merchant's memberships.

          • namestring

            Required

            What the member was called.

            ≥ 1 chars

          • emailstring · email

            Required

            The member's address.

          • rolestring · enum

            Required

            The role the member held.

            ownermanagerstaff

        • category_idstring · uuid

          RequiredNullable

          The category the product was filed under when the line was rung, for reporting. Snapshot: moving the product to another category later moves no sale. Null on an ad-hoc line or an uncategorised product.

        • category_namestring

          Required

          The category's name when the line was rung, so a report of past sales reads as they were filed. Snapshot; empty when category_id is null.

          ≤ 255 chars

        • comp_reasonstring

          Why this line was given away. Present on a comp — an item given away at no charge — and means something different from a discount, so it is reported separately. Required when the line is a comp.

          ≤ 512 chars

        • courseinteger · int32

          Nullable

          The course this line belongs to, in a full-service kitchen — starters, mains, desserts. Set on the till when ringing to a course, and used to hold or fire a course from the till. Null for a single-course counter sale or a course-less line. Held courses are not sent (sent_at null) until they are fired.

          ≥ 1

        • discountMoney

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • discount_idstring · uuid

          Nullable

          The discount definition applied to this line, for reporting. Null for a line with no discount. Snapshot — the discount is recorded so its use can be attributed even if the definition later changes.

        • discount_namestring

          The discount's name at the time the line was priced, snapshotted on the line — the reason a guest can be told, without re-resolving a definition that may have been renamed or deleted. Empty for a line with no discount.

          ≤ 200 chars

        • gift_card_codestring

          Nullable

          The code on the card being sold, when the line's product is a gift_card — typed or scanned at the till. The server issues the card (or refuses a code already live) when the order completes. Null for any other line.

          ≤ 64 chars

        • gift_card_token_hashstring

          Nullable

          The hash of the balance-page token for the card being sold: SHA-256 over the token's text, in base64url without padding. The device mints the token — 32 random bytes, unpadded base64url — and prints it on the receipt's balance link; only its hash leaves the device, so the token is never on the record of the sale, and the server checks a link by hashing the token it carries (W3C, "Good Practices for Capability URLs"). Absent leaves the card with no balance link until one is made (gift-card-balance-links). Null for any other line.

          43–43 chars · pattern ^[A-Za-z0-9_-]{43}$

        • modifiersarray of OrderLineModifier

          The options chosen on this line, snapshotted at the moment of sale. The line's unit_price already includes each option's delta.

          The server checks only the shape of these — a negative delta is refused, an option chosen twice is refused — and never refuses a sale because the menu has changed since the till synced. A sale that was correct when rung stays correct.

          • idstring · uuid

            Required

            The modifier that was chosen. Kept for reporting, never re-resolved.

          • namestring

            Required

            Option name as sold. Snapshot.

            1–255 chars

          • price_deltaMoney

            Required

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

        • multibuyMultibuyRule

          Nullable

          The product's multibuy rule as it stood when the line was rung, snapshotted on the line so the server resolves the gross by the same deal the till did — re-pricing a product never rewrites a sale that was correct. Null on a line with no deal. A rule never applies to a weighed line.

          • everyinteger

            Required

            How many units make a run; 3 is the ordinary buy-two-get-one.

            2–1000

          • priceMoney

            Required

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

        • notestring

          Free text from the till — "oat milk", "no sugar".

          ≤ 512 chars

        • originstring · enum

          Read only

          Where this line was rung from, as the server saw the writer: the till at the counter, a guest's phone on a tab, an ordering channel, an integration. It is the server's word and never the writer's, and it is how the share of a table's spend the table rang itself is told. Absent on a line recorded before origins were.

          tillcustomeronlineintegration

        • product_idstring · uuid

          Nullable

          The catalogue product, for reporting. Null for an ad-hoc line — a miscellaneous item rung up at a custom price, which every real till needs.

        • product_typestring · enum

          Required

          What the product was when the line was rung: a gift_card sold is money taken for a promise, not revenue, and a combo is a set. Square's item_type. Snapshot, copied from the product at the moment of sale; standard on an ad-hoc line.

          standardgift_cardcombo

        • quantityQuantity

          Required

          How much of something, as a decimal string in the unit_of_measure beside it (each where there is none), as Square's quantity is: three croissants are "3", 1.4 kg of beans is "1.4". A string because a JSON number is a binary float to most parsers.

          It has at most as many decimal places as its unit's base unit holds — three in each, g and ml, six in kg and l — and a finer one is refused, never rounded. Tenvelo holds every quantity as an integer of that base unit (thousandths of an each, milligrams, microlitres; docs/decisions/0063); a client that computes with one should read the digits the same way, never through a float.

          ≤ 26 chars · pattern ^-?(0|[1-9][0-9]*)(\.[0-9]{1,6})?$

        • seatinteger · int32

          Nullable

          The seat this line is for, when a table's seats are numbered. Set on the till and carried to the kitchen and to split bills. Null for a counter sale or an unnumbered seat.

          ≥ 1

        • sent_atstring · date-time

          Nullable

          When this line was sent to the kitchen — set by the till when a tab is held or a sale completed, and immutable once set. A kitchen knows what to cook from the lines of a ticket, and a new round on a tab is a new set of sent_at values rather than the old lines re-sent. Null on a line the till has not yet held or completed.

        • serialsarray of string

          The serial numbers of the units this line sold (retail item: serial numbers) — one per unit, in the order they were entered, printed on a product whose track_serial is set. Empty on any other line. A snapshot like the name and price: the record of which physical units left the shelf, so a specific unit sold is traceable to its sale.

          default []

        • taxMoney

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • tax_breakdownarray of TaxBreakdownItem

          Each rate's share of this line's tax, in the order its rule names the rates, when the line is taxed over several rates (each a separate calculation, each rounding with its own mode). Absent — null — on a line taxed at a single rate, where tax_rate_percentage and tax are the whole story.

          • amountMoney

            Required

            A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

            The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

            Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

            • amountinteger · int64

              Required

              The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

            • currencyCurrency

              Required

              ISO 4217 currency code.

              Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

              One of 182 values; see the schema.

          • inclusiveboolean

            Required

            Whether this rate is inside the price (true) or added on top (false).

          • percentagePercentage

            Required

            A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

            A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

            pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

          • rate_idstring · uuid

            Required

            The rate this share belongs to.

        • tax_inclusiveboolean

          Whether unit_price already contains the tax. Snapshot.

        • tax_rate_percentagePercentage

          A share of a whole, from "0" to "100", as a percentage in a decimal string with at most four decimal places, as Square's percentage and Stripe Tax's percentage_decimal are: UK VAT at 20% is "20", and an 8.875% US sales tax is "8.875".

          A string because a JSON number is a binary float to most parsers, and a float cannot hold most decimal fractions exactly (RFC 7493 §2.2). Tenvelo computes with a percentage as an integer in parts per million ("8.875" is 88750), which every four-place percentage is exactly. A client that computes with one should read the digits the same way, never through a float.

          pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

        • totalMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • unit_of_measurestring · enum

          Nullable

          The unit this line was sold in, snapshotted from the product at the moment of sale (the product's own unit on a product line; any unit on an ad-hoc line). Absent means each.

          eachkgglml

        • unit_priceMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • variant_idstring · uuid

          Nullable

          The variant that was sold, for reporting and stock. Null when the product itself is the sellable unit — a product with no variants, or with none picked. Like product_id, it is retained for reporting and never re-resolved: the descriptive and monetary fields on this line are the snapshot that is replayed, so a sale that was correct when rung stays correct even if the catalogue has changed since.

      • location_idstring · uuid

        Required

      • loyalty_earnedinteger · int64

        Read only

        The points this sale earned its customer, recorded on the order.

      • loyalty_spentinteger · int64

        Read only

        The points this sale redeemed from its customer, recorded on the order.

      • memberMemberSnapshot

        Nullable

        The staff member who recorded this order — the person who rang it up — as they were then; nil when no person was attributed.

        • idstring · uuid

          Required

          The roster's id, checked against the merchant's memberships.

        • namestring

          Required

          What the member was called.

          ≥ 1 chars

        • emailstring · email

          Required

          The member's address.

        • rolestring · enum

          Required

          The role the member held.

          ownermanagerstaff

      • merchant_idstring · uuid

        RequiredRead only

      • owner_memberMemberSnapshot

        Nullable

        The staff member a tab belongs to — who opened it, and whom to ask when nobody has touched it. Checked against the merchant's memberships; nil for an order that was never a tab. Set once at open and only changed through a till's explicit transfer.

        • idstring · uuid

          Required

          The roster's id, checked against the merchant's memberships.

        • namestring

          Required

          What the member was called.

          ≥ 1 chars

        • emailstring · email

          Required

          The member's address.

        • rolestring · enum

          Required

          The role the member held.

          ownermanagerstaff

      • paidMoney

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • paymentsarray of Payment

        How the sale was paid for. Present on a completed order, and the thing that makes a day's takings reconcilable: an order that says completed without saying how it was paid records that something was sold and nothing about whether any money arrived.

        An open order — a tab being split or part-paid — may also carry payments: a partial payment is appended while the tab stays open, and what remains is derived from the lines minus these payments and never stored. The server refuses a payment larger than what remains, and completes the order in the write whose payments cover the sale.

        • idstring · uuid

          The payment's id. Minted by the device, so a retry of the same tender converges on the same row instead of recording the money twice; the server mints one when a writer does not supply it. A refund names it as payment_id, and a card refund is reversed against it, so it is returned with every read of the order and never renumbered.

        • amountMoney

          Required

          The total taken by this payment, including any tip.

          Following Square: the tender's amount is what the customer parted with, and tip is the portion of it that is not for goods. Modelling it the other way — an amount that excludes the tip — means every reconciliation has to remember to add the two back together, and one place that forgets is a day's takings that do not balance.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • buyer_suppliedMoney

          Nullable

          What the customer physically handed over. Cash only.

          Recorded rather than assumed so that change is derived from it: a note tendered for a smaller sale is the ordinary case, and the drawer at close must agree with the sum of what went in.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • card_brandstring

          Read only

          The scheme the processor read off the card, in its own words ("visa", "mastercard", "amex"). Card payments only; absent where the processor reports none.

        • card_confirmationstring · enum

          Read only

          How the card payment was confirmed against the checkout the processor says took it: confirmed when the approved checkout's amount matched and it belongs to this sale, unconfirmed when it is not approved, belongs to another sale, or took a different amount. An unconfirmed sale is still recorded — the money may already have moved — but the payment is flagged for a person to reconcile. The server's word, never the till's. Absent for a payment that is not a card, and for a card the till recorded by reference on a third-party terminal, which has no checkout to confirm against.

          confirmedunconfirmed

        • card_last4string

          Read only

          The last four digits of the card that paid, as the processor masked them — what a payment shows as "Visa •• 4242", and what a person types into the order list's search to find the sale. Card payments only; absent where the processor reports none. Never the PAN.

          ≤ 4 chars

        • change_backMoney

          NullableRead only

          Change handed back, calculated by the server as buyer_supplied - amount and never accepted from a client.

          Derived rather than submitted because it is the one figure a till could get wrong in a way that balances on screen and not in the drawer.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • fingerprintstring

          Read only

          The processor's card-alias token, never the PAN, for a card payment it could identify. It is what lets a returning card be recognised without the card number. Card payments only; absent for cash and vouchers, and for a card payment the processor did not identify.

          ≤ 256 chars

        • gift_card_hold_idstring · uuid

          The hold a till took on the voucher's card before tendering it (batchCreateGiftCardHolds), which this payment settles. Absent for a voucher tendered offline, which is spent against what the till last knew of the card.

        • line_idsarray of string · uuid

          The lines this payment settled, when the till knows the split: a share pays whole lines, so a reopened tab shows the unpaid lines rather than a number, and a mistake cannot charge somebody twice (tabs item 13).

          Empty when the payment named no lines — a whole-sale tender, an even split, a card share settling what is left, and every payment recorded before this existed. Empty and absent mean the same thing and are accepted alike, and a till sends the empty array.

        • memberMemberSnapshot

          Nullable

          The member who took this tender — the terminal operator who took the tip, not whoever rang the sale. The kept tip rule follows it. Absent for a payment recorded by something that is not a person.

          • idstring · uuid

            Required

            The roster's id, checked against the merchant's memberships.

          • namestring

            Required

            What the member was called.

            ≥ 1 chars

          • emailstring · email

            Required

            The member's address.

          • rolestring · enum

            Required

            The role the member held.

            ownermanagerstaff

        • methodstring · enum

          Required

          cash — taken into the drawer. Settled by definition: nothing to capture, nothing that can later fail.

          card — captured through the PSP. Recorded here as what the terminal reported, not as proof of settlement.

          voucher — a gift card or credit note redeemed against the sale.

          account — put on a customer's account to settle later. Requires the sale to name the customer (customer_id) and the merchant to have an open customer account for them; the till chooses the account at the tender and links the sale to its customer (retail: customer accounts).

          A loyalty redemption is not a payment method any more: a reward redeems against its discount definition, the order line carries the discount, and the server spends the guest's points when the order is written. The points method was retired.

          external — money a channel took before the order reached the venue: an online storefront, a delivery platform. The merchant settles with that channel, so the tender records the platform's reference rather than a card payment this merchant never captured. Only valid on an order a channel wrote, and the reference is required.

          cashcardvoucheraccountexternal

        • pinstring

          A voucher's PIN — the scratch-off second factor that proves possession of the card whose code is in reference (gift cards item 20). Required only when the card carries a PIN (a pre-printed or merchant-supplied code); a card with a generated code needs none, and the server refuses a sale whose voucher cannot prove the PIN. Only the hash is stored and compared; the plaintext never comes back.

          ≤ 12 chars

        • referencestring

          The PSP's identifier for a card payment, or a voucher's code. Cash has neither and needs neither. Required for an external tender: it is the platform's own transaction or order reference, which is what reconciliation against that channel relies on.

          ≤ 128 chars

        • tipMoney

          Nullable

          The part of amount that is a gratuity rather than payment for goods.

          Present because hospitality is not an edge case here: a bar or restaurant tab is the core flow, and a till that cannot record a tip cannot be used in one.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

      • pickup_atstring · date-time

        Read only

        When the guest was told they could collect. Set by whoever took the order — the ordering page, or a till ringing a takeaway for collection at a time — and kept however the order is written afterwards: a later write that omits it leaves the promised time alone. Absent on an order nobody promised a time for.

      • ready_atstring · date-time

        Read only

        When the venue said an asked-for order was ready for the guest, recorded as a ready fact — the Ready button, the kitchen bumping the order's last ticket, or an integration. Absent until then, and again after a ready_undone takes it back. Read from the facts, never from whether the kitchen has any tickets for the order.

      • ready_to_pay_atstring · date-time

        Read only

        When a guest at the table said they were ready to pay (order-and-pay), on an open order. Absent until they tap; carried on the change feed as an order update, which is how the till shows the call.

      • received_atTimestamp

        RequiredRead only

        Server-assigned RFC 3339 timestamp, always UTC.

        Server-assigned because device clocks drift and cannot be trusted for ordering — a till that has been powered off for a week may come back with a clock hours out. Where the device's own view of time matters it is carried separately in client_created_at.

      • referencestring

        Short human-readable reference shown on the receipt and used by staff to find the order. Unique per location per business day.

        ≤ 64 chars

      • refundedMoney

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • rejection_notestring

        Read only

        The staff member's words, in their own voice, required when the reason is other.

        ≤ 512 chars

      • rejection_reasonstring · enum

        Read only

        Why an asked-for order was turned down, when it was. timed_out is the sweep that rejects an unanswered order past its location's deadline.

        sold_outclosedtoo_busyothertimed_out

      • service_chargeMoney

        Nullable

        The discretionary service charge added to this bill (order-ledger item 9), in the order's currency, or null when none. Never folded into goods; part of the total payments must sum to.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • service_charge_taxMoney

        Nullable

        The tax on the service charge, its own line and never folded into goods tax_total, or null when the charge is not taxed.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • service_charge_tax_class_idstring · uuid

        Nullable

        The tax class the service charge was taxed under (decision record 0054), snapshotted from the location's config at write, or null when the charge is not taxed.

      • service_charge_tax_rate_percentagePercentage

        Nullable

        The combined tax rate that applied to the service charge, or null when not taxed.

        pattern ^(100(\.0{1,4})?|(0|[1-9][0-9]?)(\.[0-9]{1,4})?)$

      • sourcestring

        Read only

        Which caller wrote the order — the device id for a pos or table order, storefront for one placed on a venue's ordering page, and the integration client id for an integration one. Set server-side from the caller, and an identifier's provenance, not a name.

      • source_namestring

        Read only

        The name the merchant gave the integration that wrote an integration order, as it was when the order was recorded; empty for any other channel.

      • statestring · enum

        Required

        open is a sale in progress, shared with the devices at its location. completed is finalised and immutable. canceled is an open order that ended without being paid. voided is a completed order reversed. Neither of the last two is deleted, so the audit trail survives.

        opencompletedcanceledvoided

      • table_idstring · uuid

        Nullable

        The table an open order is parked on, if any. Occupancy is derived from this.

      • tipsMoney

        A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

        The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

        Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

        • amountinteger · int64

          Required

          The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

        • currencyCurrency

          Required

          ISO 4217 currency code.

          Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

          One of 182 values; see the schema.

      • totalsOrderTotals

        Required

        The money on an order, broken out.

        These are computed and sent by the device, then independently recomputed by the server on receipt. A mismatch is rejected with 422 rather than quietly corrected: if the till printed a receipt showing one total and the server stored another, the merchant has an unreconcilable discrepancy and no way to know which is right. Failing loudly surfaces a till running stale tax configuration while it is still one order, not a month's worth.

        • cash_roundingMoney

          Nullable

          How much a cash settlement rounded the price, signed (docs/decisions/0015): a €10.02 bill rounded up to €10.05 has cash_rounding 3, and the cash payment's goods portion is the total plus this. The till computes it from the location's cash step; the server recomputes and rejects a mismatch. Zero on a sale no cash settles, and cards are never rounded.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • discount_totalMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • service_chargeMoney

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • service_charge_taxMoney

          Nullable

          The tax on the service charge (decision record 0054), its own line and never folded into goods tax_total. Computed server-side from the location's service-charge tax class and the sale's fulfilment and business date. Null when the charge is not taxed.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • subtotalMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • tax_totalMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

        • totalMoney

          Required

          A monetary amount in a specific currency: Square's Money, and Stripe's amount beside its currency.

          The amount is always an integer count of the currency's minor unit — pence for GBP, cents for USD. Zero-decimal currencies such as JPY have a minor unit equal to their major unit, so {"amount": 500, "currency": "JPY"} is ¥500 while {"amount": 500, "currency": "GBP"} is £5.00.

          Floating point is never used for money anywhere in this API. Binary floats cannot represent most decimal fractions exactly, so accumulating them across the line items of an order produces totals that disagree with the printed receipt by a penny. Integer minor units make every arithmetic operation exact.

          • amountinteger · int64

            Required

            The amount, as a whole number of the currency's minor unit. May be negative to express a refund, discount or credit.

          • currencyCurrency

            Required

            ISO 4217 currency code.

            Determines the minor unit that Money.amount is expressed in. Zero-decimal currencies such as JPY have a minor unit equal to the major unit.

            One of 182 values; see the schema.

      • updated_atTimestamp

        RequiredRead only

        Server-assigned RFC 3339 timestamp, always UTC.

        Server-assigned because device clocks drift and cannot be trusted for ordering — a till that has been powered off for a week may come back with a clock hours out. Where the device's own view of time matters it is carried separately in client_created_at.

      • versionVersion

        RequiredRead only

        Optimistic concurrency version, raised by the server on every write. A version is never lower than one already returned for the resource, though it may rise by more than one.

        Returned in the ETag response header as well as in the body. Send it back in If-Match on an update and the write is rejected with 412 if anyone else has written since — which is what stops two tills silently overwriting each other's edit to the same product when both come back online at once.

        ≥ 1

      • void_memberMemberSnapshot

        Nullable

        The staff member who voided this order, when it has been voided and the void was made by a person. Nil for a sale that was never voided, or one voided by something that is not a person.

        • idstring · uuid

          Required

          The roster's id, checked against the merchant's memberships.

        • namestring

          Required

          What the member was called.

          ≥ 1 chars

        • emailstring · email

          Required

          The member's address.

        • rolestring · enum

          Required

          The role the member held.

          ownermanagerstaff

      • void_notestring

        The staff member's note on the void, required when the reason is other.

      • void_reasonstring · enum

        Why this sale was voided. Set on a voided order.

        customer_canceledstaff_errorrefundother

      • voided_atstring · date-time

        Nullable

        When the sale was voided.

    • 400

      The request could not be parsed. Malformed JSON, a bad query parameter, or a header that failed to decode, among them an API-Version later than the server speaks or not a date (api-version-unknown, with the server's own in api_version).

      Distinct from 422: a 400 never reached validation, so invalid_params is absent. Retrying without changing the request will fail again, except that a request refused for its API-Version goes once the server is updated.

    • 401

      No credentials, or credentials that could not be verified — missing bearer token, malformed JWT, expired token, or a signature that failed against the issuer's JWKS.

      Refresh the token and retry once. Repeated 401 after a refresh means the device needs to re-enrol.

    • 403

      Authenticated, but not permitted. The token is valid and its merchant was resolved, but the caller's role does not allow this operation, or the target belongs to a different merchant.

      Cross-tenant access is reported as 403 on a resource the caller may not see, and as 404 where even confirming existence would leak information. Retrying will not help.

    • 410

      The request names an API-Version this server no longer serves (docs/decisions/0011). Nothing in it was read. api_version names the version the server speaks: the client is behind, and sends the request again once it is updated.

    • 415

      The request Content-Type is not supported. This API accepts application/json on all mutations.

    • 422

      The request parsed but failed validation.

      invalid_params lists every failing field with a JSON Pointer, not just the first, so a client can mark up a whole form in one pass rather than making the user fix errors one round trip at a time.

      Also returned when an Idempotency-Key is replayed with a different body, and when device-computed order totals disagree with the server's recomputation.

    • 429

      Rate limit exceeded. Honour Retry-After rather than applying your own backoff.

      A fleet of tills coming back online together after an outage is the realistic cause, which is exactly when uncoordinated client-side retry turns a brief outage into a sustained one. The limit is per process, and per site for what records trade there — a request spends its site's budget, and a till's own smaller one inside it — and per (client, merchant) for everything else; no RateLimit field is sent, so this response and its Retry-After are the whole of the contract.

    • 500

      Something failed on our side. trace_id identifies the request in our tracing — quote it in a support ticket.

      The body never carries internal detail: no SQL, no stack traces, no upstream error strings. Safe to retry with the same Idempotency-Key.

    • 503

      Temporarily unable to serve the request — a dependency is down or the service is shedding load.

      Retry with the same Idempotency-Key after Retry-After. This is always safe: a request that did take effect before the failure will be recognised as a replay.