Aller au contenu

Restaurant menu and takeaway orders ​

Connect API · https://api.conciar.com/connect/v1

Ordering for pickup from a customer app. Money is {amount, minor, currency}, VAT included. Guests and signed-in members can both order; with a bearer token the order counts towards the member's stamps and points.

INFO

La référence de l’API est en anglais.

Get the menu ​

The menu that applies now (or the first menu when none does), with categories, items and option groups. Items not available today or not sold on this channel are left out; items sold out on this channel stay in with out_of_stock: true. Names follow Accept-Language; translations holds the other languages.

GET/connect/v1/store/restaurant/menu
Clé publique ou secrèteNécessite X-Sales-Channel

Codes de statut

  • 404MENU_NOT_FOUND — the restaurant has no menu.

Bon à savoir

  • Order with an item's id (not product_id) and option ids. maximum_selections 0 means no maximum.
  • stamp_eligible is the deprecated name of earns_stamps and always has the same value.
curl "https://api.conciar.com/connect/v1/store/restaurant/menu" \
  -H "Accept: application/json" \
  -H "X-Api-Key: pk_your_publishable_key" \
  -H "X-Sales-Channel: cnct_ch_your_channel_token"
Exemple de réponse · 200
{
  "data": {
    "id": 3,
    "name": "All day",
    "start_at": null,
    "end_at": null,
    "categories": [
      {
        "id": 12,
        "code": "mains",
        "name": "Mains",
        "color": null,
        "translations": {},
        "items": [
          {
            "id": 101,
            "product_id": 9001,
            "sku": "EX-BURGER",
            "name": "Example burger",
            "description": null,
            "story": null,
            "translations": {},
            "image_url": null,
            "out_of_stock": false,
            "earns_stamps": true,
            "stamp_reward_eligible": true,
            "stamp_eligible": true,
            "earns_points": true,
            "available_from": null,
            "available_until": null,
            "price": {
              "amount": "12.50",
              "minor": 1250,
              "currency": "EUR"
            },
            "option_groups": [
              {
                "id": 40,
                "code": "extras",
                "name": "Extras",
                "translations": {},
                "is_required": false,
                "minimum_selections": 0,
                "maximum_selections": 3,
                "included_selections": 0,
                "rank": 1,
                "options": [
                  {
                    "id": 501,
                    "name": "Extra cheese",
                    "translations": {},
                    "is_default": false,
                    "rank": 1,
                    "extra_price": {
                      "amount": "1.00",
                      "minor": 100,
                      "currency": "EUR"
                    }
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
}

Get pickup hours and slots ​

Opening hours, holiday hours for the next 14 days and the pickup rules: whether ASAP is allowed, the lead time, the slot size, the last-order cutoff and how many days ahead customers may order.

GET/connect/v1/store/restaurant/pickup-info
Clé publique ou secrèteNécessite X-Sales-Channel
curl "https://api.conciar.com/connect/v1/store/restaurant/pickup-info" \
  -H "Accept: application/json" \
  -H "X-Api-Key: pk_your_publishable_key" \
  -H "X-Sales-Channel: cnct_ch_your_channel_token"
Exemple de réponse · 200
{
  "data": {
    "store": {
      "sales_channel_token": "cnct_ch_your_channel_token",
      "name": "Bistro Example",
      "address": "Example Street 1, 1000 AA Example City"
    },
    "timezone": "Europe/Amsterdam",
    "operating_hours": {
      "monday": {
        "isOpen": true,
        "is24Hours": false,
        "timeSlots": [
          {
            "openTime": "11:00",
            "closeTime": "22:00"
          }
        ]
      },
      "tuesday": {
        "isOpen": true,
        "is24Hours": false,
        "timeSlots": [
          {
            "openTime": "11:00",
            "closeTime": "22:00"
          }
        ]
      },
      "wednesday": {
        "isOpen": true,
        "is24Hours": false,
        "timeSlots": [
          {
            "openTime": "11:00",
            "closeTime": "22:00"
          }
        ]
      },
      "thursday": {
        "isOpen": true,
        "is24Hours": false,
        "timeSlots": [
          {
            "openTime": "11:00",
            "closeTime": "22:00"
          }
        ]
      },
      "friday": {
        "isOpen": true,
        "is24Hours": false,
        "timeSlots": [
          {
            "openTime": "11:00",
            "closeTime": "23:00"
          }
        ]
      },
      "saturday": {
        "isOpen": true,
        "is24Hours": false,
        "timeSlots": [
          {
            "openTime": "12:00",
            "closeTime": "23:00"
          }
        ]
      },
      "sunday": {
        "isOpen": false,
        "is24Hours": false,
        "timeSlots": []
      }
    },
    "holiday_hours": [],
    "is_open_now": true,
    "asap_enabled": true,
    "lead_time_minutes": 15,
    "slot_minutes": 15,
    "last_order_minutes_before_close": 10,
    "max_days_ahead": 0
  }
}

Place a takeaway order ​

Creates the order and starts its payment. Redirect methods return payment.payment_url (send the customer there); Apple Pay and Google Pay return the wallet details to show the sheet, then charge with POST …/payment. An order fully paid by a reward or points needs no payment (payment: null). Unpaid orders expire after 30 minutes (the default).

POST/connect/v1/store/restaurant/orders
Clé publique ou secrèteNécessite X-Sales-ChannelJeton client facultatif

Limite de débit: 10/min per key (a publishable key: per key and IP); 60/min per store (organization and sales channel)

Corps

  • itemsarrayobligatoire

    1–50 lines.

  • items[].item_idintegerobligatoire

    Menu item id.

  • items[].qtyinteger

    1–99, default 1.

  • items[].optionsinteger[]

    Option ids, up to 30, no duplicates.

  • pickup_atstring

    Date-time on the slot grid; leave out for as soon as possible.

  • customer_notesstring

    Max 500.

  • customer.first_namestring

    Required for guests (no bearer token). Max 100.

  • customer.last_namestring

    Max 100.

  • customer.emailstring

    Required for guests. Max 255.

  • payment_method_keystringobligatoire

    A key from GET /store/payment-methods, e.g. ideal, applepay.

  • payment_service_provider_keystring

    Pick the provider; otherwise the first enabled one.

  • payment_method_dataobject

    Optional. For visa, mastercard and amex its card_token is passed to the provider.

  • return_urlstring

    Required except for applepay and google_pay. Where the provider sends the customer after paying. Max 2048.

  • redeem_rewardboolean

    Members: spend a full stamp card.

  • redeem_pointsinteger

    Members: spend exactly this many points (1–100000000).

  • use_pointsboolean

    Members: spend as many points as allowed.

  • phone, birth_date, billing_addressmixed

    Only when the method's requires list asks for them (e.g. Klarna). phone max 30, birth_date max 10. billing_address: street (max 100), house_number (max 10), house_number_suffix (max 10), postcode (max 10), city (max 100), country (ISO-2).

En-têtes

  • Idempotency-Keystring

    1–64 characters. A retry with the same key and body within 24 hours returns the same order instead of a new one.

Codes de statut

  • 409IDEMPOTENCY_KEY_REUSED (same key, different body) or IDEMPOTENCY_KEY_IN_PROGRESS.
  • 422Validation (including an Idempotency-Key that is empty or longer than 64), or a code in message: STORE_CLOSED, INVALID_PICKUP_TIME, ITEM_UNAVAILABLE, INVALID_OPTIONS, NO_REWARD_AVAILABLE, NO_ELIGIBLE_ITEM, INSUFFICIENT_POINTS, POINTS_DISABLED, BELOW_MIN_REDEMPTION, EXCEEDS_MAX, NOTHING_TO_PAY, PAYMENT_METHOD_UNAVAILABLE, PAYMENT_DETAILS_REQUIRED, PAYMENT_FAILED. errors points at the field.

Bon à savoir

  • Keep order_token: it is the guest's only way to read, pay or cancel the order (header X-Order-Token).
  • status: awaiting_payment, scheduled, received, preparing, ready, collected or cancelled. pickup_number is set once the order is paid.
  • For applepay and google_pay, payment is {type: wallet, method, amount, merchant} — what the native payment sheet needs; then charge the token with POST …/payment.
curl -X POST "https://api.conciar.com/connect/v1/store/restaurant/orders" \
  -H "Accept: application/json" \
  -H "X-Api-Key: pk_your_publishable_key" \
  -H "X-Sales-Channel: cnct_ch_your_channel_token" \
  -H "Idempotency-Key: order-2026-10-16-0001" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      {
        "item_id": 101,
        "qty": 2,
        "options": [
          501
        ]
      }
    ],
    "customer": {
      "first_name": "Alex",
      "email": "alex@example.com"
    },
    "payment_method_key": "ideal",
    "return_url": "https://www.example.com/order/return"
  }'
Exemple de réponse · 201
{
  "data": {
    "order": {
      "reference": "EXAMPLE-0001",
      "pickup_number": null,
      "pickup_name": "Alex",
      "store": {
        "sales_channel_token": "cnct_ch_your_channel_token",
        "name": "Bistro Example"
      },
      "status": "awaiting_payment",
      "pickup_at": "2026-10-16T12:30:00+02:00",
      "release_at": null,
      "created_at": "2026-10-16T11:58:12+02:00",
      "customer_notes": null,
      "lines": [
        {
          "item_id": 101,
          "name": "Example burger",
          "image_url": null,
          "qty": 2,
          "selections": [
            "Extra cheese"
          ],
          "option_ids": [
            501
          ],
          "unit_price": {
            "amount": "12.50",
            "minor": 1250,
            "currency": "EUR"
          },
          "total_price": {
            "amount": "25.00",
            "minor": 2500,
            "currency": "EUR"
          }
        }
      ],
      "subtotal": {
        "amount": "25.00",
        "minor": 2500,
        "currency": "EUR"
      },
      "discount": {
        "amount": "0.00",
        "minor": 0,
        "currency": "EUR"
      },
      "total": {
        "amount": "25.00",
        "minor": 2500,
        "currency": "EUR"
      },
      "reward_redeemed": false,
      "points_redeemed": 0,
      "points_discount": {
        "amount": "0.00",
        "minor": 0,
        "currency": "EUR"
      },
      "loyalty": {
        "stamps_earned": 0,
        "points_earned": 0
      }
    },
    "order_token": "ot_example_order_token",
    "payment": {
      "type": "redirect",
      "payment_url": "https://payment-provider.example/checkout/…",
      "transaction_key": "example-transaction-key"
    }
  }
}

Get an order ​

Poll this for the order status (every 5–10 seconds is plenty).

GET/connect/v1/store/restaurant/orders/{reference}
Clé publique ou secrèteNécessite X-Sales-ChannelJeton client facultatif

Limite de débit: 30/min per key (a publishable key: per key and IP)

Paramètres de chemin

  • referencestringobligatoire

    The order reference.

En-têtes

  • X-Order-Tokenstring

    The order_token, when there is no bearer token.

Codes de statut

  • 404ORDER_NOT_FOUND.

Bon à savoir

  • Send either the bearer token of the customer who placed the order or the header X-Order-Token with the order_token returned at placement. Anything else is 404 ORDER_NOT_FOUND.
curl "https://api.conciar.com/connect/v1/store/restaurant/orders/EXAMPLE-0001" \
  -H "Accept: application/json" \
  -H "X-Api-Key: pk_your_publishable_key" \
  -H "X-Sales-Channel: cnct_ch_your_channel_token" \
  -H "X-Order-Token: ot_example_order_token"
Exemple de réponse · 200
{
  "data": {
    "reference": "EXAMPLE-0001",
    "pickup_number": 17,
    "pickup_name": "Alex",
    "store": {
      "sales_channel_token": "cnct_ch_your_channel_token",
      "name": "Bistro Example"
    },
    "status": "preparing",
    "pickup_at": "2026-10-16T12:30:00+02:00",
    "release_at": null,
    "created_at": "2026-10-16T11:58:12+02:00",
    "customer_notes": null,
    "lines": [
      {
        "item_id": 101,
        "name": "Example burger",
        "image_url": null,
        "qty": 2,
        "selections": [
          "Extra cheese"
        ],
        "option_ids": [
          501
        ],
        "unit_price": {
          "amount": "12.50",
          "minor": 1250,
          "currency": "EUR"
        },
        "total_price": {
          "amount": "25.00",
          "minor": 2500,
          "currency": "EUR"
        }
      }
    ],
    "subtotal": {
      "amount": "25.00",
      "minor": 2500,
      "currency": "EUR"
    },
    "discount": {
      "amount": "0.00",
      "minor": 0,
      "currency": "EUR"
    },
    "total": {
      "amount": "25.00",
      "minor": 2500,
      "currency": "EUR"
    },
    "reward_redeemed": false,
    "points_redeemed": 0,
    "points_discount": {
      "amount": "0.00",
      "minor": 0,
      "currency": "EUR"
    },
    "loyalty": {
      "stamps_earned": 0,
      "points_earned": 0
    }
  }
}

Pay or retry payment ​

Starts a new payment for an order awaiting payment, or charges Apple Pay / Google Pay. With apple_pay_token or google_pay_token the charge happens in this call: 200 when paid, 202 when pending, 422 PAYMENT_FAILED when declined (the order stays payable).

POST/connect/v1/store/restaurant/orders/{reference}/payment
Clé publique ou secrèteNécessite X-Sales-ChannelJeton client facultatif

Limite de débit: 10/min per key (a publishable key: per key and IP); 120/min per store (shared by payment and cancel)

Paramètres de chemin

  • referencestringobligatoire

    The order reference.

Corps

  • payment_method_keystringobligatoire

    Payment method key.

  • payment_service_provider_keystring

    Provider key.

  • payment_method_dataobject

    Optional. For visa, mastercard and amex its card_token is passed to the provider.

  • return_urlstring

    Required except for applepay and google_pay. Max 2048.

  • apple_pay_tokenobject|string

    The PKPaymentToken (object, JSON or base64).

  • google_pay_tokenstring

    tokenizationData.token (JSON or base64).

  • customer.first_name, customer.last_namestring

    Max 100 each. Only for methods that require a name; defaults to the order's.

  • phone, birth_date, billing_addressmixed

    Only when the method's requires list asks for them. Same fields as when placing the order.

Codes de statut

  • 200Wallet token charged and paid: {data: {status: "paid", order, payment}}.
  • 202Wallet token charged, still pending at the provider: {data: {status: "pending", order, payment}}.
  • 404ORDER_NOT_FOUND.
  • 409PAYMENT_FAILED — another payment for this order is in progress.
  • 422Validation, or ORDER_NOT_PAYABLE, PAYMENT_METHOD_UNAVAILABLE, PAYMENT_DETAILS_REQUIRED, INVALID_WALLET_TOKEN or PAYMENT_FAILED (a declined wallet charge also carries data with the order).

Bon à savoir

  • Send either the bearer token of the customer who placed the order or the header X-Order-Token with the order_token returned at placement. Anything else is 404 ORDER_NOT_FOUND.
curl -X POST "https://api.conciar.com/connect/v1/store/restaurant/orders/EXAMPLE-0001/payment" \
  -H "Accept: application/json" \
  -H "X-Api-Key: pk_your_publishable_key" \
  -H "X-Sales-Channel: cnct_ch_your_channel_token" \
  -H "X-Order-Token: ot_example_order_token" \
  -H "Content-Type: application/json" \
  -d '{
    "payment_method_key": "ideal",
    "return_url": "https://www.example.com/order/return"
  }'
Exemple de réponse · 201
{
  "data": {
    "payment": {
      "type": "redirect",
      "payment_url": "https://payment-provider.example/checkout/…",
      "transaction_key": "example-transaction-key"
    }
  }
}

Cancel an unpaid order ​

Only while the order is awaiting payment. Releases any reward or points held for it.

POST/connect/v1/store/restaurant/orders/{reference}/cancel
Clé publique ou secrèteNécessite X-Sales-ChannelJeton client facultatif

Limite de débit: 10/min per key (a publishable key: per key and IP); 120/min per store (shared by payment and cancel)

Paramètres de chemin

  • referencestringobligatoire

    The order reference.

Codes de statut

  • 404ORDER_NOT_FOUND.
  • 422ORDER_NOT_CANCELLABLE — already paid or no longer awaiting payment.

Bon à savoir

  • Send either the bearer token of the customer who placed the order or the header X-Order-Token with the order_token returned at placement. Anything else is 404 ORDER_NOT_FOUND.
curl -X POST "https://api.conciar.com/connect/v1/store/restaurant/orders/EXAMPLE-0001/cancel" \
  -H "Accept: application/json" \
  -H "X-Api-Key: pk_your_publishable_key" \
  -H "X-Sales-Channel: cnct_ch_your_channel_token" \
  -H "X-Order-Token: ot_example_order_token"
Exemple de réponse · 200
{
  "data": {
    "reference": "EXAMPLE-0001",
    "pickup_number": null,
    "pickup_name": "Alex",
    "store": {
      "sales_channel_token": "cnct_ch_your_channel_token",
      "name": "Bistro Example"
    },
    "status": "cancelled",
    "pickup_at": "2026-10-16T12:30:00+02:00",
    "release_at": null,
    "created_at": "2026-10-16T11:58:12+02:00",
    "customer_notes": null,
    "lines": [
      {
        "item_id": 101,
        "name": "Example burger",
        "image_url": null,
        "qty": 2,
        "selections": [
          "Extra cheese"
        ],
        "option_ids": [
          501
        ],
        "unit_price": {
          "amount": "12.50",
          "minor": 1250,
          "currency": "EUR"
        },
        "total_price": {
          "amount": "25.00",
          "minor": 2500,
          "currency": "EUR"
        }
      }
    ],
    "subtotal": {
      "amount": "25.00",
      "minor": 2500,
      "currency": "EUR"
    },
    "discount": {
      "amount": "0.00",
      "minor": 0,
      "currency": "EUR"
    },
    "total": {
      "amount": "25.00",
      "minor": 2500,
      "currency": "EUR"
    },
    "reward_redeemed": false,
    "points_redeemed": 0,
    "points_discount": {
      "amount": "0.00",
      "minor": 0,
      "currency": "EUR"
    },
    "loyalty": {
      "stamps_earned": 0,
      "points_earned": 0
    }
  }
}

Ask for the bill at a table ​

A guest at a table asks for the bill from their phone. The token comes from the table's QR code. Calling it again keeps the first time.

POST/connect/v1/store/restaurant/table/{token}/bill-request
Clé publique ou secrèteNécessite X-Sales-Channel

Limite de débit: 120/min per store

Paramètres de chemin

  • tokenstringobligatoire

    The table's QR token: the table id, a dot and 24 characters.

Codes de statut

  • 404Unknown table (or a table of another organization).
  • 422{status: false, message: "This table has no open visit."}
curl -X POST "https://api.conciar.com/connect/v1/store/restaurant/table/12.0123456789abcdef01234567/bill-request" \
  -H "Accept: application/json" \
  -H "X-Api-Key: pk_your_publishable_key" \
  -H "X-Sales-Channel: cnct_ch_your_channel_token"
Exemple de réponse · 200
{
  "status": true,
  "bill_requested_at": "2026-10-16T21:14:03+02:00"
}

Call a waiter to a table ​

A guest at a table calls a waiter from their phone. The token comes from the table's QR code. Waiters see the call until one of them handles it.

POST/connect/v1/store/restaurant/table/{token}/assistance-request
Clé publique ou secrèteNécessite X-Sales-Channel

Limite de débit: 120/min per store

Paramètres de chemin

  • tokenstringobligatoire

    The table's QR token: the table id, a dot and 24 characters.

Codes de statut

  • 404Unknown table (or a table of another organization).

Bon à savoir

  • Unlike the bill request, it does not need an open visit at the table.
curl -X POST "https://api.conciar.com/connect/v1/store/restaurant/table/12.0123456789abcdef01234567/assistance-request" \
  -H "Accept: application/json" \
  -H "X-Api-Key: pk_your_publishable_key" \
  -H "X-Sales-Channel: cnct_ch_your_channel_token"
Exemple de réponse · 200
{
  "status": true,
  "assistance_requested_at": "2026-10-16T21:14:03+02:00"
}