Skip to content

Connect an API or MCP client

Use an approved isolated tenant first. These instructions describe implemented protocols, not permission to enable an integration or a claim of provider certification. The versioned reference contains only reviewed external contracts; the internal OpenAPI inventory is not a partner API.

An authorized administrator opens BackOffice → Devices & integrations → API access → Register API client. Select an active integration registry entry, only the required data scopes and explicit locations, then review the grant. An inactive registry entry cannot receive access. Personal-data scopes need a separate PII approval; organization-wide customer access is not a location-local permission. Inspector profiles are separately time/date/location/report bounded and cannot be mixed with ordinary scopes or MCP.

Choose the client type for its actual purpose:

  • App with staff sign-in (public_pkce): a staff member approves a delegated connection. Required for MCP; no client secret. Register the client’s exact redirect URI. HTTPS is required except supported localhost loopback callbacks; wildcards and fragments are not allowed.
  • Server-to-server (confidential_machine): a server exchanges its client ID and secret using client_credentials. It cannot substitute for a delegated MCP connection.
  • API key: an opaque key sent as Authorization: Bearer <key>, not an X-API-Key header. Anyone holding it can exercise its remaining grant.

Secrets are revealed once. Store them in your integration’s secret store, not source control, browser storage, URLs, screenshots or logs. A replay of client creation does not reveal a previously returned secret again; rotate a lost one. Some separately approved connector scopes are bounded writes, not general write access. Read each scope’s consent description; a client type never grants every HTTP method or internal route.

For MCP choose analytics.mcp and only the necessary data scopes, such as reports.read. The granting staff member must retain the live report capability and location access. Answers leave Butterchop for the AI provider you selected, under that provider’s terms. Do not approve data your organization cannot share.

Copy the MCP server URL from the registered client’s details, or obtain the assigned tenant HTTPS origin and organization resource from your administrator. Do not use the account/billing host or guess an organization from a request body. The resource is the issuer’s exact /v1/orgs/{orgId} URL, not its /mcp suffix.

All identifiers and domains below are synthetic. Replace them with the approved isolated tenant’s values before running a request; the example domain does not host a Butterchop tenant.

Terminal window
RESOURCE='https://tenant.example.test/v1/orgs/10000000-0000-7000-8000-000000000001'
curl --fail-with-body --silent --show-error \
"$RESOURCE/.well-known/oauth-protected-resource"
curl --fail-with-body --silent --show-error \
"$RESOURCE/.well-known/oauth-authorization-server"

Validate the discovered issuer, resource and HTTPS origin against the tenant you intended to connect. An MCP 401 also supplies resource_metadata in WWW-Authenticate. Follow that trusted metadata to the authorization server; never send a token to an arbitrary URL copied from untrusted content.

Use an OAuth-capable MCP client or a reviewed OAuth client implementation:

  1. Generate a fresh, unpredictable verifier and state in the client. Use code_challenge = BASE64URL(SHA256(verifier)) and code_challenge_method=S256.
  2. Open the discovered authorization_endpoint with response_type=code, your client_id, the exact registered redirect_uri, requested space-separated scopes, state, challenge, explicit location selection and the discovered resource. The configured staff consent surface signs in the staff member and displays the requested grant. Do not automate approval with an owner’s password or treat a details response as consent.
  3. The staff member reviews the client, scopes and locations and chooses Approve or Deny. At the callback verify state, issuer and the exact expected redirect before accepting a code or error. A code is single-use, not an API token.
  4. POST form-encoded data to the discovered token_endpoint with grant_type=authorization_code, client_id, code, the same redirect_uri, code_verifier and resource. A public client sends no secret. Repeated form parameters are refused. Keep returned access and refresh tokens private.

If the tenant has not configured an interactive consent surface, ask its administrator to configure one; do not silently approve via an administrative API. Only the consented intersection of client scope, staff authority and location grants is usable. A successful login alone is not consent.

For a confidential server client, use form-encoded grant_type=client_credentials and the intended resource at the discovered token endpoint with its configured client authentication method. Request only granted scopes. This does not acquire staff delegation or unlock MCP.

Section titled “Read the consent copy for report, finance, promotion and staff scopes”

The staff consent surface shows each requested scope with the description that the server holds for it. The table gives the meaning of each scope that the report, finance, promotion and staff MCP tools use. The staff member approves only what the table lists. Each scope is read-only. No scope lets the client change data.

Scope Tool What the staff member approves What the scope never includes
reports.read list_reports The AI client can read the names, versions, inputs and output columns of the reports that the staff member can run. Report data, and the capability names behind a report.
tax.read get_tax_report The AI client can read tax collected, refunded and net, by tax name and rate, for up to 92 days at the granted locations. A filed return, a compliance certificate, customer tax ids and exemption documents.
finance.statements.read get_profit_and_loss The AI client can read the profit and loss statement from an accountant-approved trial-balance snapshot. The statement covers a legal entity. The client can read it only when every location of that entity is granted. Imports, approvals, journal changes, and an estimate when no snapshot exists.
promotions.read list_coupons The AI client can read coupon and automatic promotion terms, validity windows and usage counts at the granted locations. Redemptions, orders, guest details, staff notes, and any change to a promotion.
staff.performance.read get_staff_performance The AI client can read closed checks, net sales and refunds for each staff member who owns the checks, with names and ids, for up to 92 days at the granted locations. Tips, hours, pay, scores and notes. The tool does not rank or judge a person.

Before you approve, check these rules:

  • Each tool also needs analytics.mcp and a live staff capability. The granting staff member must still hold that capability at each call. A role does not need report.z for the endpoint. Any capability that backs a tool is enough, and the client then sees only the tools that capability allows.
  • staff.performance.read is employee data. A holder of pii.approve must approve the client first. The granting staff member needs report.z and labor.manage. Without the approval, the tool is not listed and a call is refused.
  • Answers leave Butterchop and go to the AI provider that you chose. Do not approve data that your organization cannot share with that provider.
  • The names of staff, reports, accounts and coupons are data that staff wrote. The AI client must not treat them as instructions.
Section titled “Read the consent copy for the delivery estimate scope”

The delivery.quote scope lets a partner client ask for a delivery fee estimate at the granted locations, through POST /v1/partner/delivery/quote (action partner.delivery_fee_estimate).

Scope Action What the staff member approves What the scope never includes
delivery.quote partner.delivery_fee_estimate The client can read non-binding delivery fee and configured feasibility estimates at the granted locations. A stored address, an order, a payment, a courier booking, a binding price and a guaranteed delivery time.

Before you approve, check these rules:

  • The estimate is not a promise. The order admission calculates the fee and the delivery window again, so a revision or an expiry time never locks a fee or a time.
  • The optional postcode is used only to match a configured delivery zone. The server does not store it and does not send it back. A postcode match is zone feasibility, not courier or street-address deliverability.
  • The calls share per-client rate limits. When the limiter is not available, the server refuses the call.
Section titled “Read the consent copy for the partner order scopes”

The orders.write scope lets a partner client create a pickup order through POST /v1/partner/orders (action partner.orders_create) and cancel it through POST /v1/partner/orders/cancellations (action partner.orders_cancel). The orders.read scope lets the client look up its order through GET /v1/partner/orders (action partner.orders_lookup). Only a delegated grant can create an order. The granting staff member is recorded as the opener.

Scope What the staff member approves What the scope never includes
orders.write Create orders at the granted locations: items, modifiers, guest name and phone, external reference. Cancel an order by external reference before it has a payment. Start a card checkout that the guest completes on the payment provider page. Prices, totals, approvals or training state, a claim that an order is paid, a delivery order, and other locations.
orders.read Read orders at the granted locations, including guest names, seat notes and card last four digits. Full card numbers and orders at other locations.

Guest data handling:

  • An order that you create through the Partner API keeps the guest name and phone number that you send. Butterchop stores them on the order. Staff of the granted locations can see them.
  • Butterchop does not put them in business events. Business events carry only identifiers, a revision and a resource link.
  • Send guest data only when the guest agreed to share it.
  • The tenant retention rules for order data apply to this data.

ACCESS_TOKEN below means a token held privately by your test client. Do not paste a live token into a shared terminal, documentation, shell history or chat; disable shell tracing and use the client secret store for real integrations.

Terminal window
curl --fail-with-body --silent --show-error "$RESOURCE/mcp" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"jsonrpc":"2.0","id":"init-1","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"Example client","version":"1.0.0"}}}'

Use the returned negotiated protocol version on subsequent requests:

Terminal window
curl --fail-with-body --silent --show-error "$RESOURCE/mcp" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-H 'MCP-Protocol-Version: 2025-11-25' \
--data '{"jsonrpc":"2.0","id":"list-1","method":"tools/list","params":{}}'
curl --fail-with-body --silent --show-error "$RESOURCE/mcp" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H 'Content-Type: application/json' \
-H 'MCP-Protocol-Version: 2025-11-25' \
--data '{"jsonrpc":"2.0","id":"locations-1","method":"tools/call","params":{"name":"list_locations","arguments":{}}}'

Choose a location returned by list_locations, not a location guessed from another tenant. Call get_sales_summary with that location_id and either omit both dates or supply both from and to as real inclusive local business days. The generated reference contains the exact strict argument schemas and limits. Unknown arguments, impossible dates and overlong ranges are errors. Money stays an exact decimal string in its location currency; never add different currencies.

Check the HTTP status and JSON-RPC error and result.isError. HTTP 200 can contain a refused tool result, exhausted quota or failed query. For successful analytics use structuredContent, its quality_state and citation’s period, source path and freshness. Distinguish complete, partial and no-data results; missing data is not zero. Tools/list is grant-filtered and is not a promise that a later call remains authorized after role, location or client revocation.

Every reviewed HTTP action names its scope, live capability, principal kind and location source. Header-scoped actions use X-Location-Id; query-scoped actions use their documented query field. Stored exports authorize their frozen resource locations, and MCP validates each tool’s location argument. None accepts an arbitrary posted organization as authority.

Result Meaning and safe next action
400 / JSON-RPC invalid params Correct the request or strict tool arguments; do not retry unchanged.
401 Wrong token kind, expired/revoked token or resource binding; reauthorize only through the intended issuer.
403 Scope, current permission, origin, location or approved resource is insufficient. Do not switch to an administrator token as a fallback.
409 For a documented mutation, refetch its revision or correct a changed-payload idempotency conflict; preserve the user’s draft.
413 / 415 Reduce the body or use the required content type.
429 Respect Retry-After and the returned RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset headers.
503 Limiting infrastructure or the feature is unavailable; fail closed and respect Retry-After.

Only use Idempotency-Key and If-Match where the operation documents them. Reuse a key for an unchanged retry after a lost response; a changed request needs a new intent/key. Never retry an unknown payment or connector result through a different tender/provider to manufacture success. A 202 acknowledges receipt, not downstream application. Staff/admin/tender paths are denied to API clients even if a guessed scope or HTTP verb appears to match an internal schema.

Honor token expires_in. Public clients rotate refresh tokens using the form-encoded refresh grant and the same resource; replace the refresh token atomically. Do not have parallel refresh requests reuse an old token: reuse revokes its token family. A confidential client secret rotation has a returned old-secret expiry; migrate the integration before that bound, not after an assumed grace period.

Revoke the token at the discovered revocation_endpoint using that client’s configured authentication, or have the administrator revoke the client in API access. A public client supplies client_id, token and resource, with no secret. Token revocation is deliberately non-enumerating; its 200 response is not proof that an arbitrary token existed. Verify the next protected call is refused. Client revocation and loss of granting-staff authority also cut off future calls. Rolling back documentation never revokes credentials.

An administrator configures Business webhooks separately from the API grant. Endpoint ownership, allowed event types, signing-key references, active client scopes and HTTPS egress policy all have to pass. Do not use an API-client secret as the webhook signing key or disclose the configured secret reference’s value.

Verify the exact raw UTF-8 request body before parsing or acknowledging it:

  1. Read single-valued x-butterchop-timestamp, x-butterchop-key-id, x-butterchop-content-sha256 and x-butterchop-signature headers.
  2. Require an active or explicitly overlapping key ID, a timestamp within ±300 seconds, a lowercase SHA-256 digest and v1= followed by 64 lowercase hex characters. Compute SHA-256 over the unmodified body bytes.
  3. Compute HMAC-SHA256(secret, timestamp + '.' + key_id + '.' + body_digest). Compare the validated equal-length digests in constant time. Reject changed body bytes, an unknown key or an expired timestamp. Never fetch a signing key from a URL supplied in the request.
  4. For the signed ownership challenge, echo the exact verified nonce in x-butterchop-webhook-challenge. A 2xx without that receipt is not ownership proof. The shared transport’s challenge type is menu.nutrition.endpoint_verification, including for business subscriptions.
  5. For event envelopes deduplicate id, track each subject’s revision and ignore older revisions. Persist receipt durably before returning 2xx. Refetch an authoritative resource only under its approved grant and documented contract; do not blindly follow arbitrary envelope URLs. Mark applied only after the consumer’s own transaction commits.

Training events do not become external production deliveries. A green test-send receipt proves only the tested receiver/signature path, not every provider, consumer application, production deployment or future delivery.