Skip to content

API & webhooks

Connect Kitchfly to other tools: Zapier, Make, Google Sheets, your accountant or a developer.

  • An API key lets another tool read your data (sales, orders, menu…).
  • A webhook makes Kitchfly notify another tool the moment something happens (a sale is closed, an order comes in, a customer opts in to marketing…).

It's included in both the Basic and Pro plans. Only an admin can create keys and webhooks, and each location has its own.

API & webhooks

Create a key

  1. Go to Settings → Integrations → API & webhooks.
  2. Tap New key, give it a name (for example "Zapier" or "My accountant") and check what it can see. The Customers and Team shifts permissions include personal data: only grant them when they're really needed.
  3. Tap Create key and copy it. This is the only time you'll see it in full.

Treat your key like a password

Anyone who has it can read the data it allows. If you think someone else has it, tap Revoke and create a new one. For now keys are read-only: they can't change anything in Kitchfly.

Create a webhook

  1. On the same screen, tap New webhook.
  2. Paste the URL the other tool gave you (it must start with https://) and choose when to notify.
  3. Save. Kitchfly shows you the signing secret (whoever builds the receiving end needs it).
  4. Tap Test to send a notice with sample data and check that it arrived.

Log shows the latest notices (kept for 30 days): whether they arrived, the response, and what was sent. If one fails, Kitchfly retries it after 1, 5, 30, 120 and 360 minutes. If a webhook fails 25 times in a row, it's turned off and you get an alert.

Webhooks created by Zapier show up here too, tagged Zapier. If you revoke Zapier's key, they're deleted as well.

Events

Event Sent when Permission
order.closed A sale is closed (paid) Sales
online_order.created An online order comes in Online orders
customer.created A new customer is added Customers
customer.opted_in A customer opts in to marketing Customers
catering.requested A catering request comes in Catering
catering.confirmed A catering event is confirmed Catering
inventory.low_stock An ingredient drops below its minimum Inventory
shift.ended Someone clocks out on the time clock Team shifts

For developers

Authentication

Base URL: https://app.kitchfly.com/api/v1. Send the key in the X-API-Key header (or Authorization: Bearer kf_live_…). Each key belongs to one location and only sees what its permissions allow. Limit: 120 requests per minute per key (429 above that).

curl https://app.kitchfly.com/api/v1/me -H "X-API-Key: kf_live_..."

Endpoints

All responses are JSON in English, amounts in US dollars, dates in ISO 8601. Lists are newest first; use limit (1–100, default 25) and since (ISO date).

Method Path Permission Returns
GET /me — Location, key name, permissions and the events it can subscribe to
GET /orders orders:read Closed orders (sales) with items, tax, tip and payments
GET /online-orders online_orders:read Online orders with customer contact
GET /customers customers:read Customers; filter with email, phone or accepts_marketing
GET /catering/events catering:read Catering requests and quotes; filter with status
GET /inventory/low-stock inventory:read Ingredients below their minimum
GET /menu menu:read Active items with category and price
GET /shifts labor:read Finished time-clock shifts with hours
GET /events — Event list and whether this key can use each one
GET /events/{event}/sample event's permission Up to 3 recent real examples (or a sample)
POST /hooks event's permission Subscribe { "url", "event" } → { "id", "secret" }
DELETE /hooks/{id} — Unsubscribe

POST /hooks and DELETE /hooks/{id} follow the REST hooks pattern that Zapier uses.

Webhook payload

{
  "id": "636b5a31-ecff-442a-8eeb-189768b308a7",
  "event": "order.closed",
  "created_at": "2026-10-22T23:45:10Z",
  "restaurant": { "id": "…", "name": "Taquería Demo", "location": "Downtown" },
  "data": { "id": "…", "number": 12, "total": 30.85, "items": [ … ] }
}

data has the same shape as the matching API endpoint. Headers: X-Kitchfly-Event, X-Kitchfly-Delivery (unique per delivery, use it to ignore duplicates) and X-Kitchfly-Signature.

Reply with any 2xx within 10 seconds. Reply 410 Gone to cancel a subscription. Anything else is retried.

Verify the signature

X-Kitchfly-Signature: t=<unix time>,v1=<signature>, where the signature is the hex HMAC-SHA256 of "<t>." + raw body with your webhook's secret.

import hashlib, hmac, time

def is_from_kitchfly(secret: str, header: str, body: bytes) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    signed = f"{parts['t']}.".encode() + body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    fresh = abs(time.time() - int(parts["t"])) < 300
    return fresh and hmac.compare_digest(expected, parts["v1"])
const crypto = require('crypto')
function isFromKitchfly(secret, header, rawBody) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')))
  const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex')
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300
  return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
}

Errors

Code Meaning
401 Missing, invalid or revoked key
402 The Kitchfly account isn't active
403 The key doesn't have the permission
429 Too many requests

FAQ

Can I connect Kitchfly to Google Sheets without coding? Yes, with Zapier or Make: create a key for them and pick the event you want to send to your sheet. See the recipes in Kitchfly + Zapier.

Is card data ever sent? No. Card numbers never leave Kitchfly; at most, the brand and last 4 digits.

How many keys and webhooks can I have? Up to 20 active keys and 100 webhooks per location.

Still need help?Use the Support button inside Kitchfly (how) or email [email protected] with your restaurant name and a screenshot. We'll get back to you as soon as possible.