The TILED API lets your website, an ordering app or another register see your products and stock, take orders, and keep everything in step with your store. No more selling the last one twice.
Base URLhttps://api.tiledcommerce.com/v1
Start here
You don't need to be a developer to connect an app. You make a key in TILED and hand it to whoever is building your website or app. They take it from there.
Open Settings → Connected appsIn your store, under “Your store”. Don't see it? Ask us to turn the API on for your store.
Add an app and pick what it's forGive it a name you'll recognise, like “Shopify store”, and choose one of the setups below.
Copy the key and send it to your developerIt's shown once. Treat it like a password. If it ever leaks, turn the app off in the same screen and the key stops working straight away.
Website stock
A website or another register that shows your stock and tells TILED when something sells.
See products & stock
Update stock
Ordering app
An online ordering app or kiosk that sends orders to your kitchen and register.
See products & stock
Look up customers
Add & update customers
See orders
Place orders
Just looks
Anything that only needs to read your catalog and stock. It can't change anything.
See products & stock
A key can never edit your products, prices, staff or settings, and it never sees your costs or margins. You can also limit a key to one location, or to only the products you've marked “On website”.
The basics
Everything lives under https://api.tiledcommerce.com/v1. Send your key as a bearer token, from your server only; never put it in a web page or a mobile app where customers could read it.
bash
# 1. Check the key works
curl https://api.tiledcommerce.com/v1/store \
-H "Authorization: Bearer $TILED_API_KEY"
# 2. Read the catalog with stock
curl "https://api.tiledcommerce.com/v1/inventory?limit=200" \
-H "Authorization: Bearer $TILED_API_KEY"
Keys
Live keys start with tk_live_. Keys from a TILED test environment start with tk_test_, so a key pasted into the wrong place is easy to spot.
Money
Always whole cents: 24900 is $249.00.
Times
ISO 8601 in UTC on the way out. On the way in, any ISO 8601 time with an offset.
Lists
Return { "items": [...], "nextCursor": "..." }. Pass cursor back until nextCursor is null. Up to 200 per page.
Retries
Calls that take stock or place an order need an Idempotency-Key header: any unique string, like your own order number. Retry with the same key and you get the first answer back, so a dropped connection never sells something twice.
Permissions
Each key only does what the merchant ticked for it. Ask for something it wasn't given and you get a 403 naming the setting to turn on.
In Settings
Scope
Lets the app
See products & stock
products:read
Products, prices, options, the menu and how many you have.
Update stock
inventory:write
Take stock off (or put it back) when something sells somewhere else. Comes with: See products & stock.
Look up customers
customers:read
Find a customer by phone or email, and see their rewards.
Add & update customers
customers:write
Sign up new customers and enroll them in rewards. Comes with: Look up customers.
See orders
orders:read
Orders and their status, as they move through the kitchen.
Place orders
orders:write
Price and place orders, check gift cards, cancel its own orders. Comes with: See orders, See products & stock.
Errors & limits
Errors come back with an HTTP status and the same shape every time. message is written so you can show it to a customer or a merchant as it is.
Follow the changes. Either poll GET /changes every minute or so with the saved cursor, or add a webhook and TILED sends the same events to you.
Tell TILED when it sells. When an order comes in on the website, call POST /inventory/adjustments with delta: -1 per item and your order number as the Idempotency-Key. If TILED sold the last one first, you get INSUFFICIENT_STOCK instead.
Webhooks
Add a webhook URL to an app in Settings → Connected apps and TILED posts changes to it within about a minute, along with a signing secret (whsec_…) shown once.
Up to 100 events per delivery, the same objects the change feed returns.
Answer with any 2xx within 10 seconds. Otherwise TILED tries again after 1, 2, 4 … minutes (up to an hour apart), and pauses after a day of failures. The merchant sees why in Settings.
An event can arrive more than once. Skip any id you've already handled.
Checking the signature
v1 is an HMAC-SHA256 of {t}.{raw body}, keyed with your signing secret, in hex. Compare it against the raw body exactly as received, before parsing it.
Stock changed: a sale, a return, a delivery, a count.
product.updated
A product
A product was added or edited.
product.deleted
{ id, sku }
A product was deleted, or taken off the website for a website-only key.
order.created
An order
An order was placed, anywhere.
order.updated
An order
An order moved along, was paid, refunded or cancelled.
customer.updated
A customer
A customer was added or edited.
customer.deleted
{ id }
A customer was erased or merged into another.
A key only gets events it's allowed to see: stock and products need “See products & stock”, orders need “See orders”, customers need “Look up customers”.
Reference
Your store
Check a key works, and see which store and locations it belongs to.
Who this key belongs to
GET/v1/store
Any key
The store's name and address slug, and what this key is allowed to do. A good first call to check a key is set up right.
Read the catalog and stock levels, and tell TILED when something sells somewhere else so it is never sold twice.
List products
GET/v1/products
Needs: See products & stock
Active products, oldest change first. To keep a copy in sync, remember the newest updatedAt you saw and pass it as updatedSince next time. A key set to “Website products only” only sees products marked On website. Cost is never included.
One row per product (or variant) per location. available is what can be sold right now: showroom + warehouse. Stock held for a customer (reserved) is already outside those numbers.
Takes stock off when something sells on your website or another register (a negative delta), or puts it back on a return (positive). A sale comes out of the showroom first, then the warehouse, the same way the TILED register does it. It shows in the product's history as “API · <app name>”.
Body
skustring
A product or variant SKU. Send this or productId.
productIdstring
With variantKey for a variant without its own SKU.
variantKeystring
Default "" (the product itself).
locationIdstring
Default: the key's location, or the store's main one.
deltaintegerrequired
-1 sold one, +1 one came back. Not 0.
reasonsale | return | adjustment
Default sale.
referencestring
Your order number, kept on the movement.
notestring
Up to 500 characters.
allowNegativeboolean
Record it even if TILED shows too little stock. Default false.
Errors
INSUFFICIENT_STOCK 409. TILED shows fewer than you asked for. details.available says how many.
IDEMPOTENCY_KEY_REQUIRED 400. The Idempotency-Key header is missing.
Everything that changed, in order. Poll it instead of re-reading the whole catalog, or let webhooks push the same events to you.
Read changes
GET/v1/changes
Any key
Events after a cursor, oldest first, each carrying the current state of what changed. Several changes to one thing inside a page collapse into one event. You only get events your key may see. Changes are kept for 7 days.
Everything an ordering app needs to show what can be ordered.
Get the menu
GET/v1/menu
Needs: See products & stock
Items with their variants, options and choices, and whether each can be made right now (available is false when an ingredient has run out). priceCents is already the sale price when there is one. A choice with included: true comes with the item; send its id in removed to leave it off. showWhen means an option or choice only applies when another option has one of those choices.
Adds a customer. Send at least a name, email or phone. marketing is the customer's own yes or no to emails and texts, recorded with the time they gave it.
Body
namestring
Or firstName and lastName.
firstNamestring
lastNamestring
emailstring
phonestring
marketing{ email: boolean, sms: boolean }
Their consent to marketing. Default no to both.
Errors
CUSTOMER_DUPLICATE 409. Someone already has that email or phone. details.customerId is who.
Their points and the rewards they can use. Pass a wallet reward, coupon or catalog reward to an order as { kind, id } in rewards. member is null when they haven't joined; enabled is false when the store has no rewards program.
Price an order, place it on the store's kitchen display and register, follow it, and cancel it if plans change.
Price an order
POST/v1/orders/quote
Needs: Place orders
Works out the total exactly as placing the order would: options, automatic promotions, discount codes, rewards, tax and gift cards. Nothing is booked. Show this total at checkout, then place the same body.
Books the order in TILED and sends it to the kitchen display. If your app already charged the customer, send payment and it's recorded under your app's name; otherwise the balance is paid at pickup. With pickupAt, the kitchen gets it prepMinutes before (up to 14 days ahead). Retrying with the same Idempotency-Key returns the order you already placed (200) instead of placing a second one.
Body
linesarrayrequired
1–100 of { sku or productId, variant?, qty, options?, removed?, note? }.
lines[].optionsarray
{ id, choices } for a pick-one or pick-several option, { id, value } for yes/no, text or number.
lines[].removedstring[]
Ids of included choices to leave off (“No onion”).
customerIdstring
Needed for rewards.
orderTypepickup | takeout | dine_in | delivery
Default pickup.
namestring
The name to call out.
tableNumberstring
deliveryAddressstring
notesstring
For the kitchen and the receipt.
pickupAtISO 8601
Ready by this time instead of now.
prepMinutesinteger
0–240. Default 15.
sendToKitchenboolean
Default true.
discountCodestring
A code from Marketing → Discount codes.
rewardsarray
Up to 5 { kind, id } from the customer's rewards.
giftCardsarray
Up to 3 { code, amountCents? }. Each pays what it can.
paymentobject
{ amountCents, label?, reference?, tipCents? } when your app already charged them.
referencestring
Your own order number.
Errors
ITEM_NOT_FOUND 409. A line's SKU isn't on the menu.
ITEM_UNAVAILABLE 409. An ingredient it needs has run out.
OPTION_REQUIRED 409. A required option wasn't answered. details.line and details.option say where.
CHOICE_UNAVAILABLE 409. A choice is out right now.
CODE_NOT_FOUND / CODE_NOT_VALID 409. The discount code can't be used.
GIFT_CARD_SHORT / GIFT_CARD_EMPTY 409. A gift card doesn't cover what you asked of it.
Cancels an order your app placed, as long as the kitchen hasn't started it. Stock, rewards and gift cards go back. Anything your app charged is marked refunded in TILED, and refundInAppCents is what you need to refund on your own payment processor. Once the kitchen has started, the store decides.
Body
reasonstring
Shown on the order.
Errors
NOT_YOUR_ORDER 409. Another app or the register placed it.
ALREADY_STARTED 409. The kitchen has started or it's been handed over.