Authentication
OrderUp's API supports two authentication paths. Pick the one that matches what you're building.
Two paths
| Path | Who uses it | What you send |
|---|---|---|
| Cookie-based JWT | Our own management and POS apps when running in a browser/web view | A signed cookie set by /api/v1/auth/login, transmitted automatically by the browser |
| API key | Third-party integrators, server-to-server clients, ISVs | An x-api-key header on every request, plus a tenant scope identifier |
If you're writing server code that talks to the API on behalf of a tenant, you want the API key path. The cookie path only makes sense if you're embedding the management UI itself or scripting against your own browser session.
API key flow (third-party integrators)
Getting a key
API keys are issued per tenant by an OrderUp admin. To request one:
- Have your tenant's account manager open a support ticket on your behalf, or open it yourself if you're authorized to act on the tenant's behalf.
- Provide:
- The tenant and restaurant(s) the key should access.
- The integration name and a brief description (one or two sentences) of what it does.
- The IP allowlist (recommended) for production traffic.
- A point of contact for security notifications.
- Once issued, the key is shown to you once. Store it in your secrets manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault — anything that isn't a flat file in a git repo). We can't retrieve it for you later; if it's lost, we rotate.
A self-serve API-key issuance flow inside the management app is on the roadmap. Until it ships, the support-ticket path is canonical.
Required headers
Every request:
x-api-key: ouk_live_<your-key>
If your key is scoped to multiple restaurants, also send:
x-restaurant-guid: <restaurant-guid>
So a complete request looks like:
curl -X GET https://api.letsorderup.com/api/v1/restaurants/abc-123/orders \
-H "x-api-key: ouk_live_a1b2c3d4..." \
-H "x-restaurant-guid: abc-123"
Permissions
API keys carry a fixed permission scope set at issuance. Common scopes:
read:orders— list and read orders.write:orders— create or update orders (used by ordering kiosks, marketplace integrations).read:menu/write:menu— for menu sync tools.read:reports— for accounting/BI integrations.
If your application calls an endpoint outside its scope, you'll get a 403 FORBIDDEN. Request a wider scope through the same support process.
Rotation
Rotate keys on any of the following:
- A team member with key access leaves.
- You suspect a key was exposed (committed to a public repo, leaked in a log).
- It's been more than 12 months since the last rotation (this is our recommendation, not an enforced expiry — but get into the habit).
To rotate:
- Request a new key. The old key keeps working.
- Roll the new key out across your infrastructure.
- Verify all your services are using the new key.
- Ask us to revoke the old key.
We can also generate a new key with a configurable overlap window (typically 7 days) so you have a clean swap window.
Cookie-based JWT flow (web apps)
If you're building a web client that holds a user session — the management app, the POS web shell — authenticate with the user's email and password (or SSO) and let the cookie do the work.
# Login
curl -X POST https://api.letsorderup.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{"email":"manager@example.com","password":"..."}'
# Subsequent calls use the cookie
curl https://api.letsorderup.com/api/v1/restaurants/abc-123/orders \
-b cookies.txt
The cookie is httpOnly and Secure — JavaScript can't read it, and it only travels over HTTPS. Your browser handles it transparently after login.
Token lifetimes:
- Access cookie: short-lived (15 minutes).
- Refresh cookie: longer-lived (30 days, sliding).
The server refreshes silently on requests that come in close to access-token expiry, so well-behaved clients don't usually need to do anything special. If you hit a 401 on a previously-working session, call /api/v1/auth/refresh — that's the explicit path back to a fresh access token.
To log out: POST /api/v1/auth/signout. This endpoint is intentionally public — it does not require a valid session, so a browser whose access cookie already expired can still complete the sign-out instead of getting a 401 that leaves the stale cookie in place. It always clears the session cookie; refresh-token revocation (which is what invalidates the session on other devices and on OrderUp's other domains) happens on a best-effort basis and only when a valid session was presented. The client should also discard any locally-cached session state.
Multi-factor authentication
User-account logins (cookie path) support TOTP-based MFA. If a user has MFA enabled, the login endpoint returns a challenge:
{
"success": false,
"error": {
"code": "MFA_REQUIRED",
"message": "Multi-factor authentication required",
"details": { "challengeId": "..." }
}
}
Submit the second factor at /api/v1/auth/mfa/verify with the challenge ID and the 6-digit code. On success you get the cookies back as if you had logged in normally.
API keys do not use MFA — they are themselves the credential. Keep them in a secrets manager and rotate.
Webhooks
Webhook signatures are a related but separate topic. If your integration receives webhooks from OrderUp, see the webhook signing-key documentation in the route reference for the relevant endpoint. Webhook payloads are signed with HMAC-SHA256 over the raw body — verify the signature before trusting any payload, and reject unsigned or stale (>5 min old) requests.
Security checklist before you go to production
- API key stored in a secrets manager, not a config file.
- IP allowlist configured if traffic comes from known addresses.
- Logs scrub the
x-api-keyheader. - Rotation procedure documented and tested.
- On-call contact for security incidents on file with us.
- Webhook signatures verified on every incoming webhook.