Authentication

Every API request is authenticated with an API key sent as a Bearer token:

http
Authorization: Bearer dk_live_your_api_key

Requests without a valid key are rejected with 401 Unauthorized — see the error catalog. The only unauthenticated endpoint is GET /v1/openapi.json — the machine-readable catalog of the whole API, readable before you have a key.

The venue's subscription must also be active: while an account is suspended or canceled, every API request is rejected with 403 Forbidden — the same lockout that applies in the DuckHub app.

Rate limits are tied to the key's venue (not your IP) and depend on the venue's plan — see Rate limits. Traffic from several hosts using the same key shares one budget.

API keys#

  • Keys have the format dk_live_ followed by 32 URL-safe base64 characters, e.g. dk_live_a1B2c3D4....
  • One key per venue. Generating a new key replaces the previous one — the old key stops working immediately.
  • Only the first 16 characters (the prefix) are stored in readable form and shown in the app for identification. The full key is stored as a hash and cannot be recovered after generation.

The full key is shown only once

Copy the key right after generating it and store it in a secrets manager. Never commit API keys to source control or embed them in client-side code. If a key leaks, revoke it or generate a new one — the old key is invalidated instantly.

Generating and revoking keys#

In the DuckHub app, open Integrations (available on every plan, including the free Egg plan):

  • Generate API key — creates the key and shows it once.
  • Regenerate — replaces the existing key (old one stops working).
  • Revoke — deletes the key; all API access stops until a new key is generated.

Read-only key#

A venue can hold a second, read-only key alongside the full one — generated from the same Integrations page. It has the same dk_live_ format, authenticates identically, but can only perform GET requests (menu, settings, reference, orders, audit log…). Any write — POST/PATCH/PUT/DELETE — is rejected with 403 and the code READ_ONLY_KEY.

Use it for anything that only needs to read: a menu widget on your website, a reporting dashboard, a monitoring script. Keep the full key for the integration that actually builds the menu. The two keys are independent — regenerating or revoking one never affects the other.

About dk_test_ keys

The API accepts the dk_test_ prefix as a valid key format, but DuckHub currently issues only dk_live_ keys — there is no separate test mode. Use a non-production venue for testing.

Request headers#

HeaderValueRequired
AuthorizationBearer dk_live_...Yes
Content-Typeapplication/jsonFor requests with a body
User-Agente.g. my-pos/1.2 (+https://example.com)Recommended — helps diagnose integration issues

Example authenticated request#

bash
curl -X POST https://api.duck-hub.com/v1/sync \
  -H "Authorization: Bearer dk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"categories":[{"externalId":"cat-mains","name":"Mains"}]}'

Authentication errors#

ResponseCause
401 Missing API keyNo Authorization header, or it does not start with Bearer
401 Invalid API key formatThe token does not start with dk_live_ or dk_test_
401 Invalid API keyUnknown, revoked or regenerated key
403 READ_ONLY_KEYA read-only key attempted a write — use the full key
403 This account's subscription is not activeSubscription suspended or canceled — applies to every endpoint