Fiest Developers

Quick start

Configure an approved sandbox client and implement Fiest OAuth safely.

This guide is the shortest safe path for implementing an approved Partner API sandbox connection. It uses the public Fiest Partner API contract and a client registration supplied privately by Fiest.

Sandbox preview

The sandbox is available to approved partners and contains synthetic test data. Production uses a separate, explicitly approved client registration. Do not substitute production URLs or credentials while following this sandbox guide.

Registration values

SettingValue
OAuth issuerhttps://auth-sandbox.fiest.io
Client IDYour Fiest-issued sandbox client ID
Client typePublic OAuth client
Client secretNone
Redirect URIYour exact registered HTTPS callback
API resourcehttps://api-sandbox.fiest.io
OpenAPI contracthttps://docs.fiest.io/openapi.yaml

Fiest shares the client ID and confirms the exact redirect URI directly with each approved partner. Do not copy values from another integration.

These sandbox endpoints do not grant access to Fiest's internal development or staging systems.

Why there is no client secret

This registration is a public OAuth client protected by PKCE S256. A static secret embedded in a distributed client cannot be kept confidential. Security instead relies on the exact redirect allowlist, high-entropy state, PKCE, one-time short-lived authorization codes, audience binding, and rotating refresh tokens.

Request these scopes:

offline_access
fiest.restaurant.read
fiest.accounting.read

Request fiest.organization.read only when Fiest has explicitly approved a Management organization integration. Add fiest.orders.read only when the reviewed client registration includes sold-order access. The initial partner sandbox flow should use one restaurant and the smallest approved scope set.

For an integration approved for accounting, order, and menu reads, the read-only scope set is:

offline_access
fiest.restaurant.read
fiest.accounting.read
fiest.orders.read
fiest.menu.read

Fiest first approves those scopes on your environment's client registration. New connections request them and obtain restaurant owner/admin OAuth consent. For an existing restaurant connection whose owner/admin has already approved accounting, orders, and menus, Fiest can record that approval in Admin and enable the reviewed read bundle on that exact connection. Its next normal OAuth refresh without a scope parameter can receive the expanded scopes; no reconnect is needed in this case. Registration approval or an API release alone does not expand customer access.

Always use the token response's returned scope to identify granted access. A refresh that explicitly requests a smaller scope set remains limited. Existing access tokens keep their original scopes until replaced, and existing accounting calls remain usable. Expired sessions, changed restaurant coverage, and Management portfolios require owner/admin OAuth authorization. An approved consent without an active refresh session also requires a fresh connection. Start your integration's existing Connect flow as the partner or authorized restaurant owner/admin. Fiest's Admin approval cannot recreate a missing token or deliver replacement credentials into your integration. After reconnecting, check the returned scope; Fiest can enable any separately approved missing reads on the new active restaurant connection. The Fiest billing operator does not need to sign in as your customer to approve access. This read-only scope set does not authorize menu edits, payment corrections, captures, refunds, or payouts.

Menu capabilities are also opt-in. Request only the scopes present in the Fiest-issued client registration:

ScopeCapability
fiest.menu.readList menus and search current menu items by stable public UUID.
fiest.menu.structure.writeCreate inactive drafts, attach existing items, and update an unshared item in an inactive draft.
fiest.menu.publish.writeSet a reviewed menu active for POS or online ordering.
fiest.catalog.import.writeInspect import capabilities, plan a bounded create-only import, apply it idempotently, and read its result.

Adding a write scope requires new consent. A read-only authorization must never be silently upgraded.

Shared sandbox writes are currently disabled

The public contract documents reviewed menu and catalog write operations, but the shared sandbox currently returns capability_disabled for them. Fiest confirms a controlled write-test environment and the exact approved scopes before write acceptance. Do not treat a documented write operation as enabled until Fiest confirms that rollout for your integration.

Use OAuth discovery instead of hardcoding authorization, token, JWKS, or revocation endpoints. Every authorization and token request must use the exact API resource above.

Complete sandbox authorization

The partner starts the connection from its own product and redirects the user to auth-sandbox.fiest.io. The user does not need to visit the production Fiest Dashboard first.

For the initial sandbox test:

  1. Expand Use an email code instead on the Fiest authorization page.
  2. Enter the pre-provisioned sandbox account email supplied by Fiest.
  3. Enter the six-digit code delivered directly to that inbox. The partner application and coding agent must never request or receive the code.
  4. Choose one reviewed test restaurant and approve the displayed permissions.
  5. Fiest redirects the browser to the exact registered partner callback.

Email verification only proves an existing Fiest identity; it never creates an account. Organization-wide authorization is introduced separately through the Fiest Management flow.

Token lifecycle

The token response is authoritative. Read expires_in, store the resulting expiry with the connection, and do not assume that a token remains valid just because it has not reached its expected expiry. A Fiest owner, administrator, or security control can revoke access earlier.

CredentialCurrent lifetimeRequired client behavior
Authorization code5 minutes, single-useExchange it promptly and exactly once with the original PKCE verifier. Never persist it as a connection credential.
Access token1 hourSend it only to the exact API resource for which it was issued. Use the returned expires_in value and obtain a replacement with the current refresh token when needed.
Refresh token90 days, rotatingStore it encrypted. Each successful refresh consumes it and returns a new refresh token with a new bounded 90-day lifetime. Replace the stored token atomically.

Refresh-token replay invalidates the associated refresh family. If refresh is rejected definitively, or no valid refresh token remains, delete unusable token material and move the connection to an explicit Reconnect Fiest state. Do not retry a consumed refresh token.

Revocation is independent of these maximum lifetimes. A revoked connection, removed membership, disabled client, or invalid authorization boundary can make otherwise unexpired tokens unusable immediately. Reconnecting starts a new OAuth authorization; it must not reuse an earlier authorization code, state, PKCE verifier, or refresh token.

Implementation sequence

  1. Generate a high-entropy OAuth state and PKCE verifier for each connection attempt.
  2. Store both server-side with a short expiry and send only the PKCE S256 challenge to Fiest.
  3. Redirect the user to the discovered authorization endpoint with the exact client ID, redirect URI, resource, and scopes.
  4. Handle both successful code callbacks and OAuth error callbacks.
  5. Consume state and the authorization code once, then exchange the code with the original PKCE verifier.
  6. Encrypt access and refresh tokens in durable server-side storage.
  7. Record the access-token expiry from expires_in. Replace rotating refresh tokens atomically. A replay or definitive refresh failure must move the connection into a clear reconnect state.
  8. Discover the current authorization boundary with GET /v1/restaurants. Never infer or accept a restaurant outside that response.
  9. Read the approved restaurant profile or accounting summary using only the published operations. Keep the documented settlement method and order origin as separate fields when importing sold-order data.
  10. If the reviewed grant includes fiest.orders.read, use find orders with its bounded filters, then pass the returned opaque orderId unchanged to get order details. Never derive, guess, increment, or expose an internal database identifier. Where the released contract includes order.paymentReferences, preserve the recorded provider identifiers and handle missing or incomplete evidence as described in provider payment references.

Direct menu-item editing

When the reviewed client has fiest.menu.read and fiest.menu.structure.write, use a discover–inspect–update sequence:

  1. Call list menus and list catalog items. Preserve the returned menuId and catalogItemId UUIDs exactly; never substitute a database sequence number or guess an identifier.
  2. Call inspect a draft menu item with both UUIDs immediately before editing. Continue only when canEdit is true, and retain the returned opaque version.
  3. Call update a draft menu item with that unchanged expectedVersion, a fresh idempotency key, explicit confirmation, and only the reviewed fields that should change.
  4. Treat precondition_failed as a signal to inspect again. Do not retry with a fabricated version. Reuse an idempotency key only when replaying the exact same update.

The server rejects edits to active or online menus, shared canonical items, stale versions, sequential IDs, and out-of-grant targets. Updating an item never publishes the menu; publishing uses its own scope and operation.

For new catalog data, call catalog import capabilities, then plan and apply the same bounded create-only document. Carry the returned plan hash and idempotency key unchanged. Use the server-issued menu, category, and item UUIDs in later calls.

Keep credentials out of the browser and logs

Never render or log access tokens, refresh tokens, authorization codes, cookies, PKCE material, customer records, or financial payloads. Retain only the safe request_id when support correlation is needed.

Prompt for a coding agent

Copy the prompt below into Claude Code, Codex, Cursor, or another coding agent. Give the agent this page and the public OpenAPI contract as its authoritative inputs.

Ready forCodexClaude Code
AI agent quick setup
Implement my approved sandbox integration with the Fiest Partner API.
Treat this quick-start page and
https://docs.fiest.io/openapi.yaml as the only authoritative contracts.

Build a server-side OAuth 2.1 authorization-code client with PKCE S256:
- issuer: https://auth-sandbox.fiest.io
- client ID: <insert the client ID supplied privately by Fiest>
- redirect URI: <insert the exact HTTPS callback registered with Fiest>
- resource/audience: https://api-sandbox.fiest.io
- scopes: use the exact approved scope set supplied by Fiest; the accounting
  baseline is offline_access fiest.restaurant.read fiest.accounting.read,
  fiest.orders.read is added only for reviewed sold-order access,
  fiest.menu.read is added only for reviewed menu reads, and menu or catalog
  write scopes are added only when Fiest explicitly approves them
- client type: public; do not invent or request a client secret

Use discovery rather than hardcoding authorization, token, JWKS, or revocation
endpoints. Generate high-entropy state and a PKCE verifier per attempt, store
them server-side with a short expiry, consume state once, and exchange each
authorization code once with the original verifier and exact resource.

Store access and rotating refresh tokens encrypted in durable server-side
storage. Treat access tokens as one-hour credentials while honoring the token
response's `expires_in` value. Replace the refresh token atomically, reject
replay, and move the connection to an explicit reconnect state when refresh
fails definitively. A successful refresh returns a new rotating refresh token
with a new bounded 90-day lifetime.
Never render or log tokens, authorization codes, PKCE material, cookies,
customer data, or financial payloads.

Implement the callback's OAuth success and error paths, then implement only
the public operations covered by the approved scopes in the supplied OpenAPI
contract. Discover the authorized restaurant ID from GET
/v1/restaurants; never accept or infer a restaurant outside that grant. For
sold-order access, pass an opaque orderId returned by findOrders unchanged to
getOrderDetails; never generate or guess one. For an approved direct menu-item
edit, preserve menuId and catalogItemId UUIDs from discovery, inspect
the exact target immediately before PATCH, and pass its opaque version as
expectedVersion with a fresh idempotency key and explicit confirmation. Never
edit a live or shared item, fabricate a version, or treat an update as
publishing. Branch on stable API error codes and retain request_id for redacted
support logs.

Add automated tests for state expiry and reuse, wrong PKCE verifier, callback
errors, one-time code exchange, exact resource/audience, refresh rotation and
replay, reconnect state, out-of-grant restaurant denial, invalid dates, 429
Retry-After handling, and redaction. Do not request unapproved write scopes,
use an MCP token, add a generic HTTP proxy, or point any test at production.

Before claiming success, report:
1. the files changed;
2. the durable state/token storage model;
3. all tests and type checks run;
4. any assumption not explicitly supported by the two provided contracts; and
5. what remains for a real browser authorization.

Do not describe type safety as verified if the strict typecheck did not run.
Report the exact blocker instead.

Acceptance checklist

Before the sandbox connection is considered complete:

  • the registered callback handles OAuth success and denial without returning 404;
  • the authorized restaurant list contains only the reviewed restaurant or organization boundary;
  • an out-of-grant restaurant returns the documented safe error;
  • two complete accounting periods reconcile;
  • when fiest.orders.read is approved, a bounded order listing returns an opaque order ID that resolves through the exact details endpoint, while a guessed or out-of-grant identifier fails safely;
  • when payment references are available in the released environment, retained provider IDs match the expected sold order and split-payment legs, and null, empty, and truncated evidence is handled without inventing identifiers;
  • when fiest.menu.read is approved, menu listing succeeds without requesting a write scope;
  • when menu editing is approved, public menu and item UUIDs survive the full list–inspect–update flow, an exact replay is idempotent, and a stale version, sequential ID, shared item, live menu, or out-of-grant target fails safely;
  • when catalog import is approved, plan and apply use the same document and plan hash, replay returns the original action, and created objects expose stable public UUIDs;
  • refresh rotation succeeds once and replay of the previous token fails;
  • revocation denies the next API request and reconnect restores the same reviewed boundary;
  • 429 handling respects Retry-After; and
  • operational logs contain request IDs but no credentials or financial data.

See stable API errors before adding retry behavior.

On this page