# Create connection Source: https://docs.maple.inc/api-reference/connections/create-connection /openapi/developer-api.json post /locations/{locationId}/connection Connects the app to a granted location as its POS receiver, provisioning and activating the integration. # Delete connection Source: https://docs.maple.inc/api-reference/connections/delete-connection /openapi/developer-api.json delete /locations/{locationId}/connection Disconnects the app from a location, removing the Developer API connection (the location can then be connected to a different POS). # Get connection Source: https://docs.maple.inc/api-reference/connections/get-connection /openapi/developer-api.json get /locations/{locationId}/connection Returns the app's connection to a granted location, if one exists. # Current app Source: https://docs.maple.inc/api-reference/general/current-app /openapi/developer-api.json get /me Returns the developer app and effective scopes for the authenticated credential. # Developer API status Source: https://docs.maple.inc/api-reference/general/developer-api-status /openapi/developer-api.json get /ping Unauthenticated readiness probe for the Developer API. # Get location Source: https://docs.maple.inc/api-reference/locations/get-location /openapi/developer-api.json get /locations/{locationId} Returns a single location the authenticated app has been granted access to. # List locations Source: https://docs.maple.inc/api-reference/locations/list-locations /openapi/developer-api.json get /locations Lists the locations the authenticated app has been granted access to. # Get location menu Source: https://docs.maple.inc/api-reference/menu/get-location-menu /openapi/developer-api.json get /locations/{locationId}/menu The location's current published menu: categories, items, and variations (prices in integer minor units), shared modifier groups, and tax/fee/discount definitions. Every object echoes the `externalId` you published it under. Requires `menus:read` and an active connection to the location. # Publish location menu Source: https://docs.maple.inc/api-reference/menu/publish-location-menu /openapi/developer-api.json post /locations/{locationId}/menu Publishes the full menu document for a connected location. Validation is all-or-nothing (a 400 lists every issue); the document is applied as a diff against the current menu, so an identical re-publish is a no-op and object identities stay stable across publishes by their `externalId`. Returns the resulting menu. Requires `menus:write` and an active connection to the location. # Accept order Source: https://docs.maple.inc/api-reference/orders/accept-order /openapi/developer-api.json post /orders/{orderId}/accept Partner accepts the order; the order is finalized and the customer confirmed. # Cancel order Source: https://docs.maple.inc/api-reference/orders/cancel-order /openapi/developer-api.json post /orders/{orderId}/cancel Partner cancels the order. # Complete order Source: https://docs.maple.inc/api-reference/orders/complete-order /openapi/developer-api.json post /orders/{orderId}/complete Partner marks the order fulfilled. # Deny order Source: https://docs.maple.inc/api-reference/orders/deny-order /openapi/developer-api.json post /orders/{orderId}/deny Partner rejects the order; it is rejected and any payment reversed. # Get order Source: https://docs.maple.inc/api-reference/orders/get-order /openapi/developer-api.json get /orders/{orderId} Returns a single order if it belongs to a location the app is connected to. # List orders Source: https://docs.maple.inc/api-reference/orders/list-orders /openapi/developer-api.json get /orders Lists orders for the locations the app is connected to as POS receiver. Without `since`, results are newest first. With `since`, results drain oldest first from that exclusive checkpoint; while `has_more` is true, repeat with `starting_after` set to the last order id from the previous page. `starting_after` must be an order owned by the app and requires `since`. Set a page size from 1 to 100. Money is in integer cents; line-item modifiers reflect the directly-selected (first-level) options. # Mark order ready Source: https://docs.maple.inc/api-reference/orders/mark-order-ready /openapi/developer-api.json post /orders/{orderId}/ready Partner marks the order ready for pickup/handoff. # Resend order Source: https://docs.maple.inc/api-reference/orders/resend-order /openapi/developer-api.json post /orders/{orderId}/resend Publishes a fresh order.notification only for a live order owned by the app connection that missed its webhook. Terminal orders cannot be resent or revived; reconcile them with GET /v1/orders?since=... and GET /v1/orders/{orderId}. # Submit order validation result Source: https://docs.maple.inc/api-reference/orders/submit-order-validation-result /openapi/developer-api.json post /orders/{orderId}/validation_result Partner reports whether an order can be accepted (item availability, pricing feasibility, POS injectability). Echo the `validation_id` from the `order.validation_requested` event so the result is bound to that attempt — a result naming an expired/older attempt is rejected (404). A valid result lets Maple send the order notification; invalid blocks it. Results expire; Maple revalidates (a new `validation_id`) before final submission. # Update order status Source: https://docs.maple.inc/api-reference/orders/update-order-status /openapi/developer-api.json post /orders/{orderId}/status Partner reports an order status transition (e.g. ready, in delivery, fulfilled). # Create webhook subscription Source: https://docs.maple.inc/api-reference/webhooks/create-webhook-subscription /openapi/developer-api.json post /webhook_subscriptions Subscribes a notification URL to event types. Returns the HMAC signing secret once. # Delete webhook subscription Source: https://docs.maple.inc/api-reference/webhooks/delete-webhook-subscription /openapi/developer-api.json delete /webhook_subscriptions/{subscriptionId} Permanently deletes the subscription; pending deliveries are abandoned. # Get webhook event Source: https://docs.maple.inc/api-reference/webhooks/get-webhook-event /openapi/developer-api.json get /webhook_events/{eventId} Retrieves a single event from the ledger, including its `data` payload. # Get webhook subscription Source: https://docs.maple.inc/api-reference/webhooks/get-webhook-subscription /openapi/developer-api.json get /webhook_subscriptions/{subscriptionId} Retrieves a single webhook subscription owned by the app. # List webhook event types Source: https://docs.maple.inc/api-reference/webhooks/list-webhook-event-types /openapi/developer-api.json get /webhook_event_types Lists the event types a webhook subscription can subscribe to. # List webhook events Source: https://docs.maple.inc/api-reference/webhooks/list-webhook-events /openapi/developer-api.json get /webhook_events The app's event ledger (most recent first, up to 50). Useful for reconciliation and debugging missed deliveries. # List webhook subscriptions Source: https://docs.maple.inc/api-reference/webhooks/list-webhook-subscriptions /openapi/developer-api.json get /webhook_subscriptions Lists the app's webhook subscriptions in the credential's environment. # Replay webhook event Source: https://docs.maple.inc/api-reference/webhooks/replay-webhook-event /openapi/developer-api.json post /webhook_events/{eventId}/replay Re-delivers the event to currently-matching subscriptions, skipping any already delivered for this event (idempotent). # Send test webhook Source: https://docs.maple.inc/api-reference/webhooks/send-test-webhook /openapi/developer-api.json post /webhook_subscriptions/{subscriptionId}/test Delivers a synthetic `webhook.test` event to the subscription and returns the delivery result. # Update webhook subscription Source: https://docs.maple.inc/api-reference/webhooks/update-webhook-subscription /openapi/developer-api.json patch /webhook_subscriptions/{subscriptionId} Updates the notification URL, subscribed event types, or enabled/disabled status. The signing secret is unchanged. # Bookings Module Source: https://docs.maple.inc/bookings/overview AI-powered table booking management through voice and SMS The Bookings Module enables Maple to handle table reservations through natural conversation. When a customer calls, the voice AI can check availability, book a table, modify an existing reservation, or cancel — all without staff involvement. The Bookings Module currently supports OpenTable as the reservation provider. Additional providers are planned for future releases. ## How it works When a customer calls to make a reservation, Maple's voice AI handles the full booking flow: The AI checks real-time availability for the requested date, time, and party size through your reservation provider. Available time slots are presented to the customer, including any experience-based options (e.g., prix fixe, brunch specials). Once the customer selects a time, the slot is temporarily held while their details are confirmed (name, phone number, party size, special requests). The reservation is created in your provider (e.g., OpenTable) and the customer receives a confirmation. ## Supported actions The voice AI can handle all common booking scenarios: | Action | Description | | ------------------- | --------------------------------------------------------- | | **New reservation** | Book a table for a specific date, time, and party size | | **Change booking** | Modify date, time, or party size of an existing booking | | **Cancel booking** | Cancel an existing reservation | | **Look up booking** | Find a reservation by confirmation number or phone number | ## OpenTable integration OpenTable is the first supported reservation provider. To use bookings with OpenTable: ### Prerequisites * ✅ Active OpenTable restaurant listing * ✅ OpenTable Restaurant ID (RID) * ✅ Maple Voice Core configured * ✅ Bookings feature enabled in your agent configuration ### Setup Provide your OpenTable Restaurant ID during onboarding. Maple connects to your OpenTable account to access real-time availability. The bookings feature is enabled in your Maple agent configuration. Your voice AI will then offer booking capabilities to callers. Call your Maple number and test the booking flow — check availability, create a reservation, and verify it appears in OpenTable. ### What syncs with OpenTable * Real-time table availability and time slots * Experience-based dining options (prix fixe, special events) * Cancellation policies * Dining area and table type preferences * Reservation confirmations and changes ## Managing bookings Bookings created through Maple appear in both: * **Your reservation provider** (e.g., OpenTable) — managed alongside walk-ins and online bookings * **Maple dashboard** — view booking history, linked calls, and analytics Each booking is linked to the call that created or modified it, providing a full audit trail. ## Troubleshooting Verify that your OpenTable Restaurant ID is correctly configured. If you recently connected, allow a few minutes for the initial sync. The time slot may have been taken between availability check and confirmation. The voice AI will offer alternative times if the selected slot becomes unavailable. Confirm that the Maple-OpenTable connection is active in the dashboard. If the issue persists, contact Maple support. Customers can call back and ask to change or cancel their booking. The AI can look up reservations by confirmation number or the phone number used when booking. ## Coming soon * **Resy** integration — book tables through Resy-connected restaurants * **Waitlist management** — add customers to waitlists during peak times ## Next Steps * [Set up Maple Voice Core](/voice-core/overview) * [Add Orders Module](/orders/overview) * [Return to Documentation Home](/) # Maple Dashboard Overview Source: https://docs.maple.inc/dashboard-overview A complete walkthrough of your Maple dashboard — what's where and how to use it. ### **Navigation** When you log into [**app.maple.inc**](https://app.maple.inc) you'll see the sidebar on the left with two sections: * **Main Menu** — top-level navigation across your account * **Location Pages** — everything specific to your active location: Orders, Bookings, Phone Calls, AI Agents, Menus, Knowledge, Analytics, and My Location At the top of the sidebar, you'll see your **merchant name** and your currently selected **location**. If you have multiple locations, click the location name to switch between them. *** ### **Maple Home** The home screen gives you a snapshot of your account status and any pending tasks. * **Pending Tasks** — items still needed before you're fully live (e.g., setting business hours, enabling call forwarding) * **Looking Ahead** — upcoming actions like going live If you see a "Complete onboarding" prompt, click it to finish any remaining setup steps before moving forward. *** ### **Location Pages** Dashboard 1 **Step 1 — Orders: Connect Your POS** Click **Orders** in the sidebar. If your POS isn't connected yet, you'll see a setup flow with three steps: Select POS 1. **Select POS** — choose and connect your point-of-sale system 2. **Payment Processing** — verify your business for payment processing 3. **Enable Orders** — activate order processing Click **Continue: Select POS** to begin. Select POS 2 You'll be redirected to a POS selection page showing all supported integrations — including **Square, Toast, Clover, Aloha Cloud, NCR Voyix, Quantic, OrderCounter**, and more. Select your POS system. Maple will redirect you to your POS provider's page, where you'll find the Maple integration — install it from there to complete the connection. If you don't use a POS, click **Continue Without POS**. If your provider isn't listed, click **I Don't See My Provider** to let us know. Once the integration is complete, your menu will automatically populate from your POS into your Maple dashboard. *** ### **Step 2 — Menus: Review Your Menu** Click **Menus** in the sidebar to review the menu that synced from your POS. Menu The menu is organized into five tabs: * **Full Menus** — top-level menus (e.g. Food & Drinks) * **Menu Categories** — sections within a menu (e.g. Appetizers, Mains) * **Menu Items** — individual items * **Modifier Groups** — groups of modifiers (e.g. sauce choices) * **Modifier Items** — individual modifier options **What to check after syncing:** * Item names are clear and customer-facing * Descriptions are accurate * Modifiers, pricing, and tax are correct * Items you don't want available are disabled #### **Menu Hours vs. Store Hours** There are two separate hour settings in Maple, and it's important to understand the difference: * **Store Hours** — your general restaurant operating hours, visible to customers. These will be displayed in **“My Location.”** * **Menu Hours** — the hours during which your Maple agent will actually accept orders. If a customer calls outside your menu hours, the agent will let them know the kitchen isn't currently taking orders. Make sure your **menu hours match the window when you actually want to accept phone orders**. These are set under each menu in the Menus tab. Just click on **Edit > Availability** to adjust the menu hours. **Menu accuracy directly impacts order accuracy.** If something is wrong in the menu, the AI will get it wrong on calls. Always review after a sync before going live. *** ### **Step 3 — Orders Tab** Once your POS is connected, orders taken by your Maple agent will appear here. Orders 1 The **Track Orders** list shows: * **Order name** — customer's name * **Phone number** — caller's number * **Amount** — order total * **Fulfillment** — pickup or delivery, ASAP or scheduled * **Payment status** — Paid or Pending * **Created at** — date and time Click any order to open the **Order Summary**, which shows the full order details including items, modifiers, payment method, fulfillment time, and caller phone number. Order Details *** ### **Step 4 — Bookings *(if enabled)*** Click **Bookings** to manage phone reservations. Bookings If you have the **Maple Bookings** module, this tab shows all incoming reservation requests from callers — synced directly with OpenTable in real time. Customers can book, modify, or cancel reservations over the phone, and everything flows into your OpenTable account automatically. If Bookings is not enabled, this page will show an upgrade option. The Bookings add-on is **\$80/mo +** **50/mo for OpenTable**. *** ### **Step 5 — Phone Calls** Click **Phone Calls** to view every call your Maple agent has handled. Phone Calls Each call card shows the caller's name, phone number, a short summary of what happened, the date and time, and whether an order was placed. Click **View Details** on any call to open the full **Call Summary**, which includes: * **Start time and call duration** * **Customer phone number** * **Call resolution** — how the call ended * **Conversation Summary** — a written AI summary of the full interaction * **Audio Recording** — play or download the full call * **Call Transcript** — complete written transcript of the conversation Call Summary Use Phone Calls regularly to monitor quality, catch any errors, and improve your agent's performance over time. *** ### **Step 6 — AI Agents** This is one of the most important tabs. Click **AI Agents** to view and configure your Maple voice agent. Click on your agent to open its settings panel. AI Agents Tab Inside the agent settings, there are six tabs: #### **Message** Set your **Welcome Message** — the first thing customers hear when they call. Keep it short, warm, and direct. Welcome Message Under **Advanced**, select additional languages your agent can speak. Options include **English, Spanish, and Mandarin Chinese.** **Cantonese** appears for accounts with beta access. #### **Call Handling** Call Handling Controls how incoming calls are routed. * **Ring Staff First** — when enabled, calls ring your staff first. If no one answers, the AI takes over. When disabled, Maple answers all calls immediately. If enabled, you can also configure the following settings: * **If Staff Doesn't Answer** — when on, the AI handles any missed call. When off, callers are told to try again later. * **Active Schedule** — choose whether Ring Staff First applies always or only during specific hours. #### **Orders** Configure your phone ordering behavior: Orders AI Agent Correcta * **Pickup Orders** — toggle on to accept pickup orders over the phone * **Pickup Notes** — add a note that appears on every pickup order * **Scheduled Orders** — allow customers to place orders for a later pickup time * **Pickup Payment** — choose how customers pay: * **Pay by Link** — Maple sends an SMS payment link. The order goes to the kitchen once paid. * **Pay in Store** — order goes straight to the kitchen. Customer pays at pickup. You can enable both options so customers can choose how they'd like to pay. **Important:** Pay by Link orders show as **Pending** until the customer pays via the SMS link. Only paid orders are sent to your kitchen. Pay in Store orders go straight to the kitchen at the time the order is placed. #### **Bookings** If you have the Bookings module, enable **Phone Reservations** here to let customers book, modify, or cancel reservations over the phone. If you're not on the Bookings plan, you'll see an upgrade prompt. #### **Actions** Configure what your AI agent can do during calls. Actions 1 **Default action:** * **Transfer to Staff** — enabled by default. Set your transfer number, max transfer attempts, and whether after-hours transfers are allowed. This is the number customers are redirected to when they ask to speak to someone at the restaurant. Your transfer number must be different from your main restaurant line — if they match, Maple will pick up the call again instead of your staff, creating a loop. **Additional actions** — click **+ Add Action** to enable: Actions 2 * **Send Order Link** — texts the customer a link to order online * **Send Booking Link** — texts the customer a link to make a reservation * **Custom SMS** — sends a custom text message to the customer * **Transfer Call** — transfers the call to a specific phone number (catering, reservations, etc.) **Note:** To set up Custom SMS, you'll need to provide your legal business name and EIN for carrier verification. Reach out to our support team at [hello@maple.inc](mailto:hello@maple.inc) to get this configured. #### **Audio & Voice** Choose your agent's voice. Four voices are available: Audio & Voice Click the speaker icon next to each voice to preview before selecting. Under **Advanced**, enable **Ambient Background Audio** to play soft background sounds during calls for a more natural experience. Click **Save Changes** when done.  Use **Try Your Agent** at the bottom left to test before going live. *** ### **Step 7 — Knowledge Base** Click **Knowledge** to manage the information your agent uses to answer customer questions beyond the menu. Each entry has a **Question** and an **Answer**. Examples: * "Are you open on Thanksgiving?" → "We are closed on most major holidays..." * "Do you offer delivery?" → "Yes, we deliver via..." * "Do you have parking?" → "Yes, free parking is available..." To add a new entry: 1. Type your question in the **Question** field 2. Type the answer in the **Answer** field 3. Click **+ Add Entry** Knowledge Base Click **+ Add Template** to use pre-built question templates as a starting point. Aim for at least **10 knowledge base entries** before going live. The more context your agent has, the better it handles real conversations. *** ### **Step 8 — Analytics** Click **Analytics** to track how Maple is performing for your restaurant. Analytics The **Analytics Dashboard** shows key metrics for your selected date range: * **Total Calls** — total number of calls handled by Maple * **Total Call Time** — combined duration of all calls * **Average Call Time** — average length per call * **Calls Transferred** — how many calls were handed off to your staff The **Total Calls Overview** chart shows call volume trends over your selected period. You can filter by **Last 7 Days, Last 30 Days**, and other date ranges. The **Key Stats Summary** card shows a high-level financial snapshot, including total sales volume processed through Maple. Check Analytics regularly — especially during your first few weeks live — to understand your call patterns, peak hours, and how well orders are converting. *** ### **Step 9 — My Location** Click **My Location** to manage your restaurant's location details. Here you'll find: * **Restaurant name and address** * **Business hours** — your general operating hours (separate from menu hours — see Step 2 for the difference) * **Location, phone number,** and website. Keep this information up to date — your agent uses it to answer questions and determine when to take orders. *** When you're ready to test your agent and switch on call forwarding, head to [Going Live](/going-live). # Conventions Source: https://docs.maple.inc/developer-api/api-reference Base URL, resource conventions, IDs, money, and list behavior shared across every Developer API endpoint. The Developer API is a JSON REST API. Every endpoint in this reference is grouped in the sidebar by resource — auth, locations, connections, menu, orders, and webhooks. This page covers the conventions they all share; the linked concept pages go deeper. ## Base URL Each environment has its own host, both served under the `/v1` prefix: ``` https://api.staging.maple.inc/v1 # Sandbox — development and testing https://api.maple.inc/v1 # Production — live traffic ``` Use the credential that matches the host (`mpk_test_…` in the sandbox, `mpk_live_…` in production). See [Environments](/developer-api/concepts/environments). ## Authentication Send a `Bearer` credential on every request: ```http theme={null} Authorization: Bearer mpk_test_… ``` Send your API key (`mpk_test_…` for the sandbox, `mpk_live_…` for production) as the bearer token. `GET /v1/me` returns the app, environment, and scopes for any key. Full detail in [Authentication](/developer-api/concepts/authentication). ## Resource conventions * **Opaque IDs** carry a type prefix — `str_` (location), `ord_` (order), `dws_` (webhook subscription), `evt_` (event), and so on. Treat them as opaque strings. * **Money is integer USD cents.** `450` means \$4.50. Never parse amounts as floats. Currency codes are always uppercase ISO‑4217 (`USD`). * **Field casing.** Menu payloads use camelCase (`externalId`, `minSelections`, `modifierGroups`); order and webhook payloads use snake\_case (`fulfillment_type`, `menu_entity_id`, `payment_status`). A line item's `menu_entity_id` carries the `externalId` you published for that menu object. * **Timestamps** on events and orders are Unix seconds (the `created` field). * **Object typing.** Most resources carry an `object` field (`order`, `location`, `event`, …) so you can tell them apart. ## Lists List endpoints return an envelope with an `object` of `list` and a `data` array: ```json theme={null} { "object": "list", "data": [ /* … */ ] } ``` Lists return a **bounded window** with a `has_more` flag rather than a total count: * `GET /v1/orders` returns up to 100 orders across your connected locations. Newest first by default; see the catch-up parameters below. * `GET /v1/webhook_events` returns up to 50 events, most recent first. * `GET /v1/locations` and `GET /v1/webhook_subscriptions` return the full set for your app. ### Draining orders after downtime `GET /v1/orders` takes three optional query parameters, built for reconciling a backlog: | Parameter | Meaning | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `since` | Exclusive ISO 8601 (UTC) checkpoint. With `since`, results are **oldest first** so you can drain forward without skipping orders that share a timestamp. | | `starting_after` | The last order id (`ord_…`) from the previous page. Requires `since`, and the order must belong to your app. | | `limit` | Page size, 1–100. Defaults to 100. | Request `GET /v1/orders?since=&limit=100`, then repeat with `starting_after` set to the last returned order id while `has_more` is true. There is no `location_id` filter — filter client-side on `location_id`. To make Maple redeliver a webhook rather than pull the order yourself, use [`POST /v1/orders/{orderId}/resend`](/developer-api/guides/receive-orders#catching-up-after-downtime) for a live order, or the [event ledger and replay](/developer-api/concepts/webhooks#the-event-ledger) when the original event identity matters. ## Errors Errors use standard HTTP status codes with a JSON body carrying a stable `_tag` and a human-readable `message`. Branch on the tag, not the message. The full catalog is in [Errors](/developer-api/concepts/errors). ## Rate limits There are no published per-app rate limits today. Be a good citizen — respond to webhooks asynchronously, avoid tight polling loops (you don't need to poll; orders are pushed), and retry `5xx` responses with exponential backoff and jitter. # Changelog Source: https://docs.maple.inc/developer-api/changelog Notable changes to the Maple Developer API. Changes to the Developer API surface — new endpoints, new event types, and behavior changes — are recorded here. The [endpoint reference](/developer-api/api-reference) always reflects the current state. * **Delivery addresses** — the order resource and the `order.notification` payload now carry `delivery_address` (street, unit, city, state, ZIP, and the customer's delivery instructions in `notes`). It is `null` for pickup orders and for delivery orders with no stored address. See [Receiving orders](/developer-api/guides/receive-orders#step-4--read-the-order). * **Order catch-up** — `GET /v1/orders` accepts `since`, `starting_after`, and `limit`. With `since`, results drain oldest first from an exclusive checkpoint so you can page through a backlog after downtime. See [Lists](/developer-api/api-reference#lists). * **Order resend** — `POST /v1/orders/{orderId}/resend` publishes a fresh `order.notification` for one live order that missed its webhook, without changing order state. Requires `webhooks:write`; terminal orders can't be resent. * **Denser webhook retries** — a failed delivery is now retried up to 9 times (was 6), with the early attempts inside the six-minute POS decision window. See [Retries and auto-disable](/developer-api/concepts/webhooks#retries-and-auto-disable). The Maple Developer API is available for POS and platform partners. * **Authentication** — API keys (`mpk_test_…` for the sandbox, `mpk_live_…` for production) with scoped access. * **Locations and connections** — list granted locations and connect as a location's order receiver. * **Orders** — receive `order.notification`, read the full order, and decide it with accept / deny / ready / complete / cancel / status. Optional pre-validation. * **Menu** — publish a location's full menu as one JSON document keyed by your own external IDs, and read it back. * **Webhooks** — subscribe to event types, verify HMAC-signed deliveries, and replay from the event ledger. # Authentication Source: https://docs.maple.inc/developer-api/concepts/authentication Every request carries a Bearer API key. The key selects the environment and carries the scopes your app holds. Every request to the Developer API carries a `Bearer` API key in the `Authorization` header: ```bash theme={null} # Sandbox curl https://api.staging.maple.inc/v1/me \ -H "Authorization: Bearer mpk_test_..." ``` A key answers three questions at once: **which app** you are, **which environment** you belong to (sandbox or production), and **which scopes** you hold. Verify any key with `GET /v1/me`, which returns exactly that. Each environment has its own base URL — `https://api.staging.maple.inc/v1` for the sandbox and `https://api.maple.inc/v1` for production. Use the key that matches the host. See [Environments](/developer-api/concepts/environments). ## API keys Maple issues your API keys during onboarding. | Key | Environment | Base URL | | ------------ | ----------- | ---------------------------------- | | `mpk_test_…` | Sandbox | `https://api.staging.maple.inc/v1` | | `mpk_live_…` | Production | `https://api.maple.inc/v1` | Send the key as the bearer token on every request, against the base URL for its environment. Keep keys server-side; never embed them in a client app or commit them to source control. Narrowing an app's scopes takes effect immediately for its existing keys. **Keys are managed by the Maple team.** Maple issues your keys during onboarding; there's no self-serve key rotation yet. If a key is lost or compromised, [contact us](https://maple.inc/get-started) for a replacement. ## Scopes Access is scoped, so your app holds only the permissions it needs: | Scope | Grants | | ---------------------------------------- | -------------------------------------- | | `locations:read` | List and read granted locations | | `connections:read` / `connections:write` | Read or manage the location connection | | `orders:read` / `orders:write` | Read orders or submit order decisions | | `menus:read` / `menus:write` | Read or publish a location's menu | | `webhooks:read` / `webhooks:write` | Read or manage webhook subscriptions | A request missing a required scope returns `403` with code `insufficient_scope`. A key used against the wrong environment returns `403` with code `wrong_environment`. See [Errors](/developer-api/concepts/errors). Check what a key can do without making a real call: `GET /v1/me` returns the app, its environment, and its effective scopes. ## OAuth **Under construction.** OAuth-based access (merchant-delegated tokens and `client_credentials` grants) is not part of the generally available Developer API yet. Use API keys for now. If your integration needs OAuth, talk to the Maple team — this section will expand when the flow is finalized. # Organizations, merchants, and locations Source: https://docs.maple.inc/developer-api/concepts/entities How Maple structures the businesses you integrate with — and why the Developer API works at the location level. Maple organizes every business into a three-level hierarchy. You'll mostly work with the bottom level — locations — but understanding the whole shape prevents wrong assumptions about what an ID refers to and what access you have. ```mermaid theme={null} flowchart TD Org[Organization] --> M1[Merchant] Org --> M2[Merchant] M1 --> L1[Location] M1 --> L2[Location] M2 --> L3[Location] ``` ## The three levels The top-level account — a brand group or company. An organization contains one or more merchants. A business under an organization (for example, a single restaurant brand). A merchant owns billing and payment setup, and contains one or more locations. One physical restaurant — the unit the Developer API works with. A location belongs to exactly one merchant. Its ID looks like `str_…`, and the API exposes it as the `location` resource. ## Cardinality, and why it matters * An organization has **many** merchants; a merchant has **many** locations. * A location belongs to **exactly one** merchant, and a merchant to **exactly one** organization. These don't move — a location can't be reparented to another merchant. * **Operational data lives at the location.** Orders, menus, connections, and webhooks are all scoped to a location, not to a merchant or organization. Two locations under the same merchant are independent as far as your integration is concerned. ## What the Developer API exposes The Developer API surfaces **locations**. The `location` resource carries the location's ID (`str_…`), name, status, timezone, phone, and address — not its parent merchant or organization. When you list locations, connect, receive orders, or publish a menu, you're always operating on a single location by its `str_…` ID. **Access is per-location.** A merchant grants your app access to specific locations, one at a time. Holding a grant to one location gives you no access to its siblings under the same merchant — each location is granted (and connected) on its own. See [How Maple works](/developer-api/how-maple-works) for grants and connections. ## Location status A location's `status` tells you whether it's open for orders: | Status | Meaning | | ---------- | ---------------------------------------------- | | `active` | Live and accepting orders | | `paused` | Temporarily not accepting orders | | `inactive` | Not yet live (setup incomplete) or deactivated | Respect it — don't expect orders from, or route work to, a location that isn't `active`. ## The connection lifecycle Your access to a location moves through four moments, and three webhook events mark them: A merchant grants your app access to a location. You receive **`store.provisioned`**, and the location appears in `GET /v1/locations`. You can read it — but orders don't route to you yet. You call `POST /v1/locations/{id}/connection` to become the location's order receiver. The connection's `status` becomes `active`, and **`store.status.changed`** fires with `status: "connected"`. Orders now route to you. You (or Maple) remove the connection with `DELETE`. **`store.status.changed`** fires with `status: "disconnected"` and orders stop routing to you. The grant remains, so you can reconnect later. The merchant revokes the grant. You receive **`store.deprovisioned`** and lose access to the location entirely. A location has at most one connected app per environment, so a `POST` to a location another app already holds returns `409`. See [Webhooks](/developer-api/concepts/webhooks) to subscribe to these events. ## Identifiers you'll see | Resource | ID prefix | In the Developer API? | | -------------------- | --------- | ----------------------------------------------------- | | Location | `str_…` | Yes — the `location` resource and every `location_id` | | Order | `ord_…` | Yes | | Webhook subscription | `dws_…` | Yes | | Event | `evt_…` | Yes | Merchant and organization IDs exist internally but aren't part of the Developer API surface — you address everything by location. # Environments and test mode Source: https://docs.maple.inc/developer-api/concepts/environments Two environments, each with its own host. Build against the sandbox, then point at production to go live. Maple runs two fully isolated environments, each with its own base URL and its own credentials: | Environment | Base URL | Credential | | -------------- | ---------------------------------- | ------------ | | **Sandbox** | `https://api.staging.maple.inc/v1` | `mpk_test_…` | | **Production** | `https://api.maple.inc/v1` | `mpk_live_…` | You develop and test entirely in the **sandbox** — the Maple team provisions it for you and issues your sandbox credentials. When your integration is approved, you point the same code at **production** with your live key. The two environments never share data: a connection, subscription, or order in the sandbox is invisible to production, and the reverse. The only differences between environments are the **base URL** and the **credential**. Your request and response shapes, webhook signing, and the order loop are identical — so going live is a configuration change, not a rewrite. ## Why this matters The sandbox lets you exercise the full order loop against data that can't affect a real merchant or charge a real customer. Once your webhook handler verifies signatures correctly and you've driven orders end to end, switching to production is a base-URL-and-credential swap. ```mermaid theme={null} flowchart LR subgraph Sandbox [Sandbox · api.staging.maple.inc] SK[mpk_test_ key] --> SD[(sandbox data)] end subgraph Production [Production · api.maple.inc] LK[mpk_live_ key] --> LD[(live data)] end ``` ## Telling environments apart in your code The sandbox and production are **separate deployments on different hosts**, so a request or webhook belongs to whichever environment its host and credential do — you don't infer it from the payload. Where you do want it explicitly: * `GET /v1/me` returns the credential's `environment` (`test` or `live`). * The order resource carries `livemode` — `true` in production, `false` in the sandbox. Use a separate webhook subscription per environment, and point each at the matching base URL. The delivered event doesn't carry an environment field — the endpoint that receives it already tells you which environment it came from. ## A test-first workflow Point your client at `https://api.staging.maple.inc/v1` with your `mpk_test_…` key. Connect to the sandbox location Maple grants you, subscribe a webhook, and exercise the full order loop. `POST /v1/webhook_subscriptions/{id}/test` delivers a signed `webhook.test` event so you can confirm signature verification and your `2xx` response before any real order exists. Once your integration is approved, Maple issues a `mpk_live_…` key. Switch the base URL to `https://api.maple.inc/v1` and the credential to your live key, then re-run your setup — connect the live location, subscribe a live webhook. Your code is otherwise unchanged. ## Going-live checklist * Your client's base URL and credential both point at the same environment. * Your webhook handler verifies the HMAC signature and rejects bad or stale signatures. See [Webhooks](/developer-api/concepts/webhooks). * You dedupe deliveries on the envelope `id` (delivery is at-least-once). * You respond `2xx` quickly and do slower work asynchronously. * Decision calls are retried safely on transient errors (they're [replay-safe](/developer-api/concepts/idempotency)). * You store the live signing secret (`mwhsec_…`) securely — it's shown only once. # Errors Source: https://docs.maple.inc/developer-api/concepts/errors Standard HTTP status codes with a JSON body carrying a stable machine-readable tag and a human-readable message. The Developer API uses conventional HTTP status codes and returns a JSON body on every error. The body carries a stable `_tag` you can switch on and a `message` meant for your logs: ```json theme={null} { "_tag": "DeveloperApiForbidden", "code": "insufficient_scope", "message": "Missing required scope: menus:write" } ``` Branch on `_tag` (and `code` where present), never on the `message` text — messages may change, tags won't. ## Status codes | Status | Meaning | What to do | | ------ | ------------------------------------------------------------------ | ------------------------------------------------------------- | | `400` | The request is malformed or references invalid values | Fix the request; don't retry unchanged | | `401` | Missing, malformed, or unrecognized credential, or an inactive app | Check the `Authorization` header and key | | `403` | Valid credential, but not allowed (see `code` below) | Adjust scopes or environment | | `404` | The resource doesn't exist or isn't visible to your credential | Verify the id and that you're connected | | `409` | The request conflicts with current state | Resolve the conflict (e.g. the location is already connected) | | `5xx` | A problem on Maple's side | Retry with exponential backoff | `4xx` bodies are safe to surface to your own logs and dashboards. `5xx` responses should be retried with backoff — the [order decision](/developer-api/guides/receive-orders#step-5--decide-and-report-progress) and webhook replay endpoints are replay-safe, so retrying them is harmless. ## Error tags | `_tag` | Status | Notes | | -------------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------- | | `DeveloperApiBadRequest` | 400 | Malformed request, or invalid values such as unknown event types. For menu publishing, the message lists every validation issue. | | `DeveloperApiUnauthorized` | 401 | The bearer credential is missing, malformed, expired, or belongs to an inactive app. | | `DeveloperApiForbidden` | 403 | Carries a `code`: `insufficient_scope` or `wrong_environment`. | | `DeveloperApiNotFound` | 404 | The resource doesn't exist or your credential can't see it. | | `DeveloperApiConflict` | 409 | The request conflicts with current state, e.g. connecting a location another app already holds. | ### The `403` codes A `DeveloperApiForbidden` always tells you *why*: * `insufficient_scope` — the credential is valid but lacks a scope the endpoint requires. Check `GET /v1/me` against the [scopes table](/developer-api/concepts/authentication#scopes). * `wrong_environment` — you used a test credential against live data or vice versa. The credential's prefix fixes its environment. ## Handling errors well * **Switch on `_tag`/`code`, log the `message`.** The tag is your control flow; the message is for humans debugging. * **Don't retry `4xx` unchanged.** They mean the request needs to change. The one nuance: a `409` may clear once the conflicting state is resolved. * **Retry `5xx` with exponential backoff.** Add jitter to avoid retry storms. * **Treat write retries as safe.** Order decisions and webhook replay are [replay-safe](/developer-api/concepts/idempotency), so a retry after a timeout won't double-apply. # Idempotency and replay safety Source: https://docs.maple.inc/developer-api/concepts/idempotency How Maple makes retries safe without an idempotency key — replay-safe decisions, diff-applied menus, idempotent replay, and dedupe on your side. Networks fail mid-request. The question that matters is: if you retry, will something happen twice? With Maple, the writes you'll retry most are built to be safe to repeat — so you can retry on a timeout without reconciling first. There is **no `Idempotency-Key` header** on this API. You don't generate or send idempotency keys. Safety is a property of each operation, described below — not something you opt into per request. ## Order decisions are replay-safe Repeating an order decision — `accept`, `deny`, `ready`, `complete`, `cancel`, or `status` — returns the same acknowledgement without applying the side effect twice: ```json theme={null} { "object": "order_decision", "order_id": "ord_...", "decision": "accept", "status": "received" } ``` If you send `accept` and the response times out, send it again. The order is accepted exactly once, and you get `{ "status": "received" }` either way. This makes a simple retry-on-transient-error loop correct without any bookkeeping on your side. ## Publishing a menu is a diff A menu publish describes the desired state of the whole menu and is applied as a diff against what's currently published, keyed by your `externalId`s: * Re-publishing an **identical** document is a no-op. * Object identities stay stable across publishes by `externalId`, so republishing doesn't recreate or churn objects. * Validation is all-or-nothing — a `400` changes nothing, so a failed publish leaves the menu exactly as it was. So if a publish times out, re-sending the same document is safe. See [Publish a menu](/developer-api/guides/publish-menu). ## Replaying an event is idempotent `POST /v1/webhook_events/{eventId}/replay` re-delivers an event only to subscriptions that haven't already received it. Subscriptions that already got it are skipped, so replaying after an outage won't double-deliver to healthy endpoints. ## Your side: dedupe deliveries The one place you must add idempotency is your **webhook handler**. Delivery is at-least-once, so the same event can arrive more than once. Dedupe on the envelope `id`: ```ts theme={null} async function handleEvent(event: { id: string; type: string; data: unknown }) { if (await alreadyProcessed(event.id)) return; // no-op on a repeat await process(event); await markProcessed(event.id); } ``` Make the work itself idempotent where you can — for example, key your own order records by Maple's `order_id` so a duplicate `order.notification` updates rather than duplicates. Don't rely on event ordering; reconcile against `GET /v1/orders/{orderId}` when sequence matters. See [Webhooks](/developer-api/concepts/webhooks#delivery-guarantees). ## Summary | Operation | Safe to retry? | Why | | ------------------ | -------------- | ------------------------------------------------------------ | | Order decisions | Yes | Replay-safe; repeats return `received` with no double effect | | Menu publish | Yes | Diff-applied; identical re-publish is a no-op | | Event replay | Yes | Skips subscriptions already delivered to | | Receiving webhooks | You dedupe | At-least-once delivery — dedupe on event `id` | # Money and amounts Source: https://docs.maple.inc/developer-api/concepts/money Every amount in the API is an integer in the currency’s minor units. No floats, no rounding surprises. Every monetary value in the Developer API is an **integer in the currency's minor units** — cents for USD. There are no decimals and no floating-point amounts anywhere in the API. ``` 450 = $4.50 (USD, 2 minor-unit digits) ``` This is deliberate: representing money as integers avoids the rounding errors that come from floating-point math, so the total you read is exactly the total the customer was charged. ## In orders On the order resource, every amount is an integer in USD cents, and `totals.currency` tells you the currency: ```json theme={null} "totals": { "currency": "USD", "subtotal": 525, "tax": 42, "surcharge": 0, "tip": 0, "delivery_fee": 0, "delivery_tip": 0, "total": 567 } ``` Line items follow the same rule: `base_price` (per unit, before modifiers), `tax`, and each modifier's `price` change are all integer cents. **Totals are computed by Maple and are authoritative.** `total` equals subtotal + tax + surcharge + tip + delivery fees. You never recompute a customer-facing price — you read it. See [How Maple works](/developer-api/how-maple-works#who-owns-what). ## In menus When you publish a menu, prices are an `amount` object that pairs the integer with its currency: ```json theme={null} { "amount": { "amountMinor": 450, "currency": "USD" } } ``` `amountMinor` is the integer in the currency's smallest unit, and `currency` is the uppercase ISO‑4217 code (`USD`). For USD that's cents — send integer cents and you're done. **Multi-currency is under construction.** Today the Developer API operates in **USD only**: publish menus in `USD`, and order totals come back in `USD`. The menu model already accepts non-USD amounts and per-currency profiles (the menu's `currencies` collection, with minor-unit digits and rounding per currency), but applying multi-currency pricing through the order loop is coming soon. Build against USD for now. For reference, minor-unit digits vary by currency — the model is built to handle this once multi-currency lands: | Currency | Minor-unit digits | `amountMinor` for 5 units | | -------- | ----------------- | ------------------------- | | USD | 2 | `500` (\$5.00) | | JPY | 0 | `5` (¥5) | | KWD | 3 | `5000` (KD 5.000) | ## Rounding Because every amount is an integer, there's no rounding in transit — the number you read is exact. Rounding only happens when Maple derives a new amount, such as a percentage discount or a tax line. The default is **banker's rounding** (round half to even), which avoids the upward bias of always rounding `.5` up. You can override it per currency through the currency profile's rounding mode, but half-even is the default — assume it when you reconcile totals on your side. ## Formatting for display To show an amount, divide by 10 raised to the currency's minor-unit digits: ```ts theme={null} function format(amountMinor: number, currency: string, digits = 2): string { return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amountMinor / 10 ** digits); } format(567, 'USD'); // "$5.67" ``` Don't hardcode division by 100 if you handle currencies with a different exponent — drive it off the currency. # Order lifecycle Source: https://docs.maple.inc/developer-api/concepts/order-lifecycle Every status an order moves through, how your decisions drive it, and the fulfillment and payment fields it carries. An order moves through a defined set of states. Maple creates it and handles payment and customer-facing transitions; you drive fulfillment by accepting it and reporting progress. This page is the reference for every status, the transitions between them, and the related fields on the order resource. To build the loop, see [Receive and decide orders](/developer-api/guides/receive-orders). ## Statuses The order resource's `status` is always one of these nine values: | Status | Meaning | Set by | | -------------------- | ----------------------------------------- | ----------------------------------------- | | `PENDING` | Created and awaiting a decision | Maple (initial state) | | `ACCEPTED` | You accepted the order | your `accept` / `status: ACCEPTED` | | `AUTO_ACCEPTED` | Accepted automatically at submission | Maple — treat it like `ACCEPTED` | | `READY` | Ready for pickup or courier handoff | your `ready` / `status: READY` | | `IN_DELIVERY` | Out for delivery | your `status: IN_DELIVERY` | | `FULFILLED` | Completed | your `complete` / `status: FULFILLED` | | `REJECTED` | Declined, or couldn't be submitted to you | your `deny` / `status: REJECTED` | | `STORE_CANCELLED` | Cancelled after acceptance by the store | your `cancel` / `status: STORE_CANCELLED` | | `CUSTOMER_CANCELLED` | The customer cancelled | Maple | `FULFILLED`, `REJECTED`, `STORE_CANCELLED`, and `CUSTOMER_CANCELLED` are **terminal** — an order in one of these states won't change again. You set status through the [decision endpoints](/developer-api/guides/receive-orders#step-5--decide-and-report-progress). `PENDING`, `AUTO_ACCEPTED`, and `CUSTOMER_CANCELLED` are system states you'll observe but never set yourself. ## How it flows ```mermaid theme={null} stateDiagram-v2 [*] --> PENDING PENDING --> ACCEPTED: accept PENDING --> REJECTED: deny ACCEPTED --> READY: ready READY --> IN_DELIVERY: status (delivery) READY --> FULFILLED: complete IN_DELIVERY --> FULFILLED: complete ACCEPTED --> STORE_CANCELLED: cancel READY --> STORE_CANCELLED: cancel FULFILLED --> [*] REJECTED --> [*] STORE_CANCELLED --> [*] ``` The happy path is `PENDING → ACCEPTED → READY → FULFILLED`, with `IN_DELIVERY` between `READY` and `FULFILLED` for delivery orders. From `PENDING` you either accept or reject. After accepting, you can still cancel (`STORE_CANCELLED`) up until the order is fulfilled. The customer cancelling (`CUSTOMER_CANCELLED`) can interrupt any non-terminal state, and arrives as an `order.cancelled` webhook. Transitions are validated — a decision that isn't legal from the current state is rejected. Because every decision is [replay-safe](/developer-api/concepts/idempotency), repeating one is harmless. ## How your decisions map to status | Call | Resulting status | | ---------------------------- | --------------------------------------------------------------------------------------------------- | | `POST /orders/{id}/accept` | `ACCEPTED` | | `POST /orders/{id}/deny` | `REJECTED` | | `POST /orders/{id}/ready` | `READY` | | `POST /orders/{id}/complete` | `FULFILLED` | | `POST /orders/{id}/cancel` | `STORE_CANCELLED` | | `POST /orders/{id}/status` | the value you send (`ACCEPTED`, `READY`, `IN_DELIVERY`, `FULFILLED`, `REJECTED`, `STORE_CANCELLED`) | ## When the webhooks fire This is where each webhook lands across one order's life. Dashed arrows are webhooks Maple sends you; solid arrows are calls you make back. ```mermaid theme={null} sequenceDiagram participant C as Customer participant M as Maple participant You as Your app C->>M: Places an order M-->>You: order.created opt You subscribed to validation M-->>You: order.validation_requested You->>M: validation_result (valid / invalid) end M-->>You: order.notification You->>M: accept M-->>You: order.paid You->>M: ready, then complete opt Customer or store cancels M-->>You: order.cancelled end ``` 1. **`order.created`** — the order now exists. Fires whether or not you use validation. 2. **`order.validation_requested`** *(only if you subscribed)* — Maple asks you to confirm the order is fulfillable and waits for your `validation_result`. An `invalid` result rejects the order here, so it never reaches the notification. 3. **`order.notification`** — the order is handed to you to fulfill. You `accept` (or `deny`), then report `ready` and `complete`. 4. **`order.paid`** — payment settled. Its position varies: a pay-by-link order may be paid before the notification, while a pay-in-store order is paid afterward — don't assume it lands at a fixed point. 5. **`order.cancelled`** — the customer or store cancelled. This can arrive almost any time after creation, including after you've started fulfilling. Stop when it does. None of your own transitions (`accept`, `ready`, `complete`) come back as webhooks, and there's no event for every status change — see below. ## Webhooks don't track every transition There is no webhook for every status change. Maple emits a fixed set of order events — `order.notification`, `order.created`, `order.paid`, `order.cancelled`, and (if you subscribe) `order.validation_requested`. The transitions **you** drive — `accept`, `ready`, `complete` — aren't echoed back to you, and there's no event for reaching `IN_DELIVERY` or for payment moving to `refunded`, `voided`, or `failed`. So the **order resource is the source of truth for current state, not the event stream.** When you need to know where an order stands, read `GET /v1/orders/{orderId}`. The webhooks tell you something happened; the resource tells you the state. See [Webhooks](/developer-api/concepts/webhooks). ## Fulfillment type Every order carries a `fulfillment_type`, one of: | Value | Meaning | | ---------- | ----------------------------------------------------------- | | `pickup` | The customer collects the order | | `delivery` | The order is delivered; this is where `IN_DELIVERY` applies | Delivery orders also carry `delivery_address` — street, unit, city, state, ZIP, and the customer's delivery instructions in `notes`. It is `null` for pickup orders and for delivery orders with no stored address. See [Receiving orders](/developer-api/guides/receive-orders#step-4--read-the-order). ## Payment is read-only Maple owns the customer payment lifecycle end to end. Payment is **never something you create or change** — there is no payment endpoint. You only ever read it, as fields on the order: ```json theme={null} "payment_status": "paid", "payment": { "provider": "stripe", "status": "paid", "payment_link_url": "https://..." } ``` `payment_status` and `payment.status` are the same value, one of: | Payment status | Meaning | | -------------------- | ---------------------- | | `pending` | Awaiting payment | | `paid` | Paid | | `failed` | Payment attempt failed | | `voided` | Authorization voided | | `refunded` | Fully refunded | | `partially_refunded` | Partially refunded | `payment_link_url` is the Maple-hosted link the customer pays through. It's `null` for pay-in-store orders and before a link has been created. Treat all of this as authoritative and read-only — see [How Maple works](/developer-api/how-maple-works#who-owns-what). # The menu model Source: https://docs.maple.inc/developer-api/concepts/the-menu-model How a Maple menu is structured, how to map your own catalog onto it, and the rules that prevent wrong assumptions. A menu is the structured description of everything a customer can order at a location: the items, how they're priced, how they're customized, and which taxes and fees apply. You publish it as one JSON document, and Maple keys every object off the **external IDs you assign**. This page explains the model and how to map your own catalog onto it. The [Publish a menu](/developer-api/guides/publish-menu) guide covers the request flow, [Menu recipes](/developer-api/guides/menu-recipes) has worked examples, and the [endpoint reference](/developer-api/api-reference) lists every field. ## One menu per location Each location has exactly **one** menu. There's no concept of multiple named menus (a separate "breakfast menu" and "dinner menu") for a location — time-of-day differences are expressed *within* the single menu using [availability windows](#availability-and-dayparting). Publishing replaces that one menu as a whole (applied as a diff — see [below](#publishing-replaces-the-whole-menu)). Maple keeps version history internally and always serves the current version, but from your side the model is simple: **one location, one menu, which you publish in full.** If your own system models several menus per location, flatten them into one Maple menu before publishing — typically as separate categories with their own availability windows. ## The tree A menu is a tree of three nested objects, with shared definitions referenced from inside it: ```mermaid theme={null} flowchart TD Cat[Category] --> Item[Item] Item --> Var[Variation · carries the price] Item -.modifierGroups.-> MG[Modifier group] Var -.modifierGroups.-> MG MG --> Opt[Modifier option] Opt -.nested.-> MG Item -.taxCategoryId / taxRateIds.-> Tax[Tax category & rates] Item -.feeIds.-> Fee[Fees] ``` * **Category** — a menu section (Drinks, Mains). Can be dayparted so it only appears in certain windows. * **Item** — a product. Has one or more variations and may carry modifier groups, tax, and fees. * **Variation** — a buyable form of an item (Small / Large, or just "Regular"). **The price lives here.** Every item has at least one. * **Modifier group** — a set of choices (Milk, Toppings) with selection rules. Defined once and shared, or inline on an item. Options can themselves carry nested modifier groups. ## Mapping your own catalog Most integrators already have a menu model. Here's how typical concepts map — getting this right up front avoids the most common mistakes: | Your concept | Maps to | Notes | | ------------------------------------------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------- | | Menu section / heading | **Category** | Order matters; categories can be dayparted. | | Product / dish | **Item** | A name and description; not where the price lives. | | Size / option that changes the base price (Small/Large) | **Variation** of the item | Not a separate item. Every item needs ≥1 variation, even if it's just "Regular". | | Add-on / customization (extra shot, no onions) | **Modifier option** in a modifier group | Group carries the selection rules; option carries any price change. | | A reusable choice set used on many items (Milk) | **Shared modifier group** referenced by `groupId` | Define once, reference everywhere. | | Combo / build-your-own with sub-choices | **Nested modifier groups** | Options can carry their own modifier groups. | Common wrong assumptions to avoid: a price does **not** live on the item (it lives on the **variation**); a size is **not** a separate item (it's a variation); and there is **one** menu per location (dayparting is availability windows, not separate menus). ## External IDs are yours Every object — category, item, variation, modifier group, option, tax rate, fee — carries an `externalId` that **you** assign and own. Maple never changes it. This is the backbone of the model: * Re-publishing with the same `externalId` updates the same object instead of creating a duplicate. * Order line items reference the menu by these IDs (`menu_entity_id`), so an incoming order maps directly back to your catalog. * Maple also mints its own IDs (`item_…`, `var_…`, `ctg_…`) in responses for reference, but you address everything by your `externalId`. * **Objects reference each other by `externalId` too.** When a modifier group reference uses `groupId`, an item points at a tax rate with `taxRateIds`, or a promotion names its discount with `discountId`, those values are the `externalId`s you assigned — not Maple's minted IDs. Use IDs that are stable in your own system (a SKU, a primary key) — not the display name, which can change. ## Pricing Prices are objects, not bare numbers, so the model can express more than a flat amount. The base shape is an amount in **integer minor units** with a currency: ```json theme={null} { "amount": { "amountMinor": 450, "currency": "USD" } } ``` The price object also supports price types (`fixed`, `variable` open-amount, `per_unit` for weighed items, `bulk` quantity tiers), tax-inclusive pricing, per-currency overrides, and a compare-at (strikethrough) amount. For the common case — a fixed price in one currency — you only need `amount`. See [Money and amounts](/developer-api/concepts/money). ## Modifiers A modifier group has selection rules and a set of options. The rules are richer than a simple min/max, which is what lets you express things like "choose up to 3, but no more than 2 of the same": | Field | Controls | | --------------------------------------------- | -------------------------------------------------- | | `minSelections` / `maxSelections` | Total selections allowed (counting quantities). | | `minUniqueSelections` / `maxUniqueSelections` | How many *distinct* options may be chosen. | | `freeSelectionCount` | How many selections are free before charges apply. | | `allowedQuantities` | Permitted per-option quantities. | | option `minQuantity` / `maxQuantity` | Bounds on a single option. | Reference a shared group from an item or variation by `groupId`, or define one inline. The two shapes are mutually exclusive in a single entry — a reference carries only `groupId`; a definition carries `name` and `options`. Mixing them is rejected rather than silently truncated. Options can carry their own nested modifier groups for build-your-own flows. See [Menu recipes](/developer-api/guides/menu-recipes) for worked examples. Order resources currently expose the directly-selected, first-level modifiers on each line item. Deeper nested selections aren't expanded into the order resource yet. ## Tax and fees These are top-level definitions you attach to items by ID: * **Tax categories and rates** — rates can be `percentage`, `flat`, or `bracket`-based, on a configurable base, inclusive or exclusive. Attach with `taxCategoryId` / `taxRateIds`. * **Fees** — surcharges and deposits (a bottle deposit or CRV), attached with `feeIds`. * **Discounts, promotions, and coupons** — optional top-level collections for price reductions. Most menus need a single tax rate and no fees; the richer constructs are there when a location needs them. ## Availability and dayparting Availability windows are how you express time-of-day menus — **this replaces the idea of multiple menus.** * A **category** with an availability window only appears during it (breakfast until 11:00). * An **item** can carry its own windows too. * An object with no availability is always available. Each window is a day plus a local time range: * `dayOfWeek` — `0` (Sunday) through `6` (Saturday). Add one window per active day. * `startTime` / `endTime` — local `HH:MM`, 24-hour. Windows are evaluated in the **menu's timezone**, set by the top-level `timezone` field (IANA, e.g. `America/New_York`). It defaults to UTC if unset, so set it on your first publish — see [Set the timezone for availability](/developer-api/guides/publish-menu#set-the-timezone-for-availability). A "daily special" or breakfast section is a category (or item) with the right windows, living in the one menu. See the [daily-specials recipe](/developer-api/guides/menu-recipes#availability-daily-specials). ## Stock status Stock status is `in_stock`, `out_of_stock`, or `low_stock`. On publish, **omitting it preserves** the current value; brand-new objects default to `in_stock`. Use it to 86 an item without republishing the whole menu's structure. ## Publishing replaces the whole menu You always send the **entire menu** as the desired state. Maple applies it as a diff keyed by `externalId`: * Validation is all-or-nothing — a `400` lists every issue and changes nothing. * An identical re-publish is a no-op, and object identities stay stable, so you can publish on every menu change without churn. So the simplest integration re-publishes the full menu whenever your source changes. See [Publish a menu](/developer-api/guides/publish-menu). # Webhooks Source: https://docs.maple.inc/developer-api/concepts/webhooks Subscribe to event types, verify HMAC-signed deliveries, dedupe at-least-once delivery, and replay from the event ledger. Webhooks are how Maple pushes things to you — a new order, a status change, a finished menu sync. You register an HTTPS endpoint and the event types you care about; Maple signs each event and delivers it, retrying on failure and keeping a ledger you can replay from. You never poll. ## The event envelope Every delivery has the same Stripe-style envelope. The `data` payload is event-specific: ```json theme={null} { "object": "event", "id": "evt_...", "type": "order.notification", "created": 1765432100, "data": { "order_id": "ord_...", "location_id": "str_..." } } ``` Unique event id. **Dedupe on this** — delivery is at-least-once. The event type. Switch on it to route the event. Unix seconds when the event was created. Event-specific payload. `order.notification` carries the full order content; the lifecycle events (`order.created`, `order.paid`, `order.cancelled`) carry summary fields. See [Webhook events](/developer-api/webhook-events) for each payload, and fetch `GET /v1/orders/{orderId}` for authoritative current state. ## Event types Subscribe only to what you act on. The live catalog is always at `GET /v1/webhook_event_types`: | Type | When it fires | | ---------------------------- | -------------------------------------------------------------------------------------- | | `order.validation_requested` | Maple asks you to validate an order before notifying you | | `order.notification` | An order is handed to you to fulfill — **the event you act on** | | `order.created` | An order was created — a lifecycle signal for analytics, thinner than the notification | | `order.paid` | Payment settled (can be after the handoff) | | `order.cancelled` | The order was cancelled — stop fulfilling it | | `store.provisioned` | A location was provisioned to your app | | `store.deprovisioned` | A location was deprovisioned from your app | | `store.status.changed` | A connected location's status changed | | `menu.sync.completed` | A menu sync completed for a location | | `menu.sync.failed` | A menu sync failed for a location | `webhook.test` is also delivered on demand by the test endpoint, so you can verify a handler before any real traffic. These are discrete events, not a status feed. Maple doesn't send a webhook for every order status change — the transitions you drive yourself (`accept`, `ready`, `complete`) aren't echoed back, and there's no per-transition event. For an order's current state, read `GET /v1/orders/{orderId}`. See the [Order lifecycle](/developer-api/concepts/order-lifecycle#webhooks-dont-track-every-transition). For what each order event carries and which to subscribe to, see [Webhook events](/developer-api/webhook-events#order-events). ## Subscribing ```bash theme={null} curl -X POST $MAPLE_BASE/webhook_subscriptions \ -H "Authorization: Bearer $MAPLE_KEY" \ -H "Content-Type: application/json" \ -d '{ "notification_url": "https://your-app.example.com/maple/webhooks", "event_types": ["order.notification", "order.cancelled"] }' ``` ```json Response theme={null} { "object": "webhook_subscription.created", "subscription": { "object": "webhook_subscription", "id": "dws_...", "environment": "test", "status": "enabled", "...": "..." }, "signing_secret": "mwhsec_..." } ``` The `signing_secret` (`mwhsec_…`) is returned **once, at creation, and never again.** Store it securely now. If you lose it, rotate by creating a new subscription. The `notification_url` must be public HTTPS — private and internal addresses are rejected. Manage subscriptions with `GET`, `PATCH` (update the URL, event types, or `enabled`/`disabled` status), and `DELETE` on `/v1/webhook_subscriptions/{id}`. Updating a subscription leaves its signing secret unchanged. ### Multiple subscriptions You can register more than one subscription. Every **enabled** subscription whose `event_types` include a fired event gets its own signed delivery, each with its own signing secret — so overlapping `event_types` across subscriptions are allowed. This lets you fan out by destination: for example, point order events at your fulfillment service and `menu.sync.*` events at a separate back-office endpoint. [Replay](#the-event-ledger) follows the same routing and skips any subscription that already received the event. ## Verifying the signature Each delivery carries two headers: * `maple-webhook-id` — the event id. * `maple-webhook-signature` — `t=,v1=`. The HMAC-SHA256 signature is computed over a signed string that binds the timestamp, the subscription, and the destination URL to the body — so a captured signature can't be replayed against a different subscription or URL: ``` {timestamp}.{subscription_id}.{notification_url}.{raw_body} ``` Recompute it with your signing secret and compare in constant time. Always use the **raw, unparsed request body** — re-serializing JSON will change the bytes and break the signature. ```ts theme={null} import { createHmac, timingSafeEqual } from 'node:crypto'; function verifyMapleWebhook(params: { signatureHeader: string; // maple-webhook-signature subscriptionId: string; // your subscription id (dws_…) notificationUrl: string; // the exact URL you registered rawBody: string; // the unparsed request body signingSecret: string; // mwhsec_… toleranceSeconds?: number; // default 300 }): boolean { const parts = Object.fromEntries(params.signatureHeader.split(',').map((p) => p.split('='))); const timestamp = Number(parts.t); const provided = parts.v1 ?? ''; // Reject stale deliveries to prevent replay. const skew = Math.abs(Math.floor(Date.now() / 1000) - timestamp); if (!Number.isFinite(timestamp) || skew > (params.toleranceSeconds ?? 300)) return false; const signed = `${timestamp}.${params.subscriptionId}.${params.notificationUrl}.${params.rawBody}`; const expected = createHmac('sha256', params.signingSecret).update(signed).digest('hex'); return expected.length === provided.length && timingSafeEqual(Buffer.from(expected), Buffer.from(provided)); } ``` ## Delivery guarantees * **At-least-once.** The same event can arrive more than once. Dedupe on the envelope `id` and make your handler idempotent. * **Respond fast.** Return a `2xx` quickly, then do slower work asynchronously. Any non-`2xx` (or a timeout) counts as a failed delivery. * **Order is not guaranteed.** Don't assume events arrive in the order they occurred; reconcile against the order resource when sequence matters. ### Retries and auto-disable Each event is delivered with up to **9 attempts** — the first immediately, then with increasing backoff. The early attempts fit inside the six-minute POS decision window, while the long tail supports reconciliation after a real outage: | Attempt | Delay after previous | | ------- | -------------------- | | 1 | immediate | | 2 | 10 seconds | | 3 | 30 seconds | | 4 | 2 minutes | | 5 | 5 minutes | | 6 | 15 minutes | | 7 | 1 hour | | 8 | 3 hours | | 9 | 6 hours | A non-`2xx` response (or a timeout — the per-attempt limit is 15 seconds) fails that attempt. An event that fails **all 9** attempts counts as one fully-failed delivery. After **5 consecutive fully-failed deliveries** — five separate events that each exhausted every attempt — the subscription is automatically **disabled**; a single successful delivery resets the counter to zero. Re-enable it with a `PATCH` setting `status` back to `enabled` once your endpoint is healthy, then [replay](#the-event-ledger) anything you missed. ## The event ledger Every event is recorded, so a missed or failed delivery is recoverable. * `GET /v1/webhook_events` — your recent events, most recent first (up to 50). Useful for reconciliation and debugging. * `GET /v1/webhook_events/{eventId}` — a single event, including its full `data` payload. * `POST /v1/webhook_events/{eventId}/replay` — re-deliver the event to currently-matching subscriptions. **Idempotent**: subscriptions that already received it are skipped, so replaying is safe. If your service was down long enough to miss an order, use the ledger replay first when you want the original event identity. For a direct catch-up, use `since` as your last successful checkpoint and drain forward: request `GET /v1/orders?since=&limit=100`, then repeat with `starting_after=` while `has_more` is true. With `since`, results are oldest first, so this reaches the entire backlog without skipping orders that share a timestamp. Fetch the authoritative order resource, then call `POST /v1/orders/{orderId}/resend` only for a live order that missed its webhook. Resend creates a fresh signed `order.notification` with a new event identity and never changes order state. Terminal orders (`REJECTED`, `CUSTOMER_CANCELLED`, or `STORE_CANCELLED`) cannot be resent or revived; reconcile them with `GET /v1/orders?since=...` and `GET /v1/orders/{orderId}`. ## Testing your handler ```bash theme={null} curl -X POST $MAPLE_BASE/webhook_subscriptions/{id}/test \ -H "Authorization: Bearer $MAPLE_KEY" ``` This delivers a signed `webhook.test` event and returns whether it was delivered and the HTTP status your endpoint returned: ```json theme={null} { "object": "webhook_test_result", "event_id": "evt_...", "delivered": true, "response_status": 200 } ``` Use it to confirm — before any real order — that your endpoint is reachable, verifies the signature, and returns `2xx`. ## Checklist Verify the HMAC signature on every delivery against the raw body, and reject stale timestamps. Dedupe on the envelope `id`; make handlers idempotent. Return `2xx` fast; process asynchronously. Subscribe only to the event types you handle. Monitor for auto-disabled subscriptions and replay from the ledger after an outage. # End-to-end example Source: https://docs.maple.inc/developer-api/guides/end-to-end-order A complete walkthrough from sandbox key to a fulfilled order, in one place. **Under construction.** This page will grow into a single, copy-along walkthrough that takes one order from a fresh sandbox key all the way to `FULFILLED`, with every request and webhook shown in sequence. For now it links the pieces together; the runnable end-to-end script is still being written. This tutorial ties the individual guides into one narrative. If you want the reference for any step, follow the links — each lands on the page that covers it in depth. ## What you'll build A minimal but complete ordering integration: connect a sandbox location, publish a small menu, receive a real order over a webhook, and drive it to `FULFILLED`. ## Steps Get a sandbox key and make your first authenticated call. Follow the [Quickstart](/developer-api/quickstart) through listing locations and connecting one. Publish a small menu so the order you receive references items you recognize. See [Publish a menu](/developer-api/guides/publish-menu). Sandbox orders come through the same path as production — a customer places an order at the location. During onboarding, Maple configures a **voice agent** (a phone number) on your sandbox location, so the way to generate a test order is to **call that number and place an order**, just as a customer would. The order flows through Maple and is pushed to your endpoint as an `order.notification`. If you don't know your sandbox location's number, [ask the Maple team](https://maple.inc/get-started). Verify the signature and read the order. See [Receive and decide orders](/developer-api/guides/receive-orders#step-3--verify-every-delivery). Accept, mark ready, then complete — watching the status move `PENDING → ACCEPTED → READY → FULFILLED`. See the [Order lifecycle](/developer-api/concepts/order-lifecycle). ## Next Until this walkthrough is complete, the [Quickstart](/developer-api/quickstart), [Receive and decide orders](/developer-api/guides/receive-orders), and [Publish a menu](/developer-api/guides/publish-menu) guides cover the same ground in depth. # Menu recipes Source: https://docs.maple.inc/developer-api/guides/menu-recipes Worked menu fragments for the scenarios real restaurants need — multi-select modifiers, nested choices, dayparted specials, and happy-hour discounts. These are copy-and-adapt fragments for common menu scenarios. Each shows only the relevant part of the menu document — drop it into the full structure from [Publish a menu](/developer-api/guides/publish-menu). For the model behind them, see [The menu model](/developer-api/concepts/the-menu-model). All prices are integer minor units (`450` = \$4.50), and every object carries an `externalId` you own. ## Multi-select: choose up to 3, max 2 different "Pick your toppings — up to 3 total, but no more than 2 different kinds." The total count and the distinct count are separate rules: ```json theme={null} { "externalId": "grp-toppings", "name": "Toppings", "minSelections": 0, "maxSelections": 3, "maxUniqueSelections": 2, "options": [ { "externalId": "top-mushroom", "name": "Mushroom", "maxQuantity": 3, "price": { "amount": { "amountMinor": 150, "currency": "USD" } } }, { "externalId": "top-pepperoni", "name": "Pepperoni", "maxQuantity": 3, "price": { "amount": { "amountMinor": 200, "currency": "USD" } } }, { "externalId": "top-olives", "name": "Olives", "maxQuantity": 3, "price": { "amount": { "amountMinor": 100, "currency": "USD" } } } ] } ``` * `maxSelections: 3` caps the **total** quantity selected. * `maxUniqueSelections: 2` caps the number of **distinct** options. A guest can take 2× Mushroom + 1× Olives (3 total, 2 kinds), but not three different toppings. * `maxQuantity: 3` on each option allows doubling or tripling a single topping. Make the first selections free with `freeSelectionCount`. For example `"freeSelectionCount": 1` charges only from the second topping onward. ## Nested modifiers A choice that opens further choices — pick a side, and if it's the salad, pick a dressing. Options can carry their own modifier groups: ```json theme={null} { "externalId": "itm-combo", "name": "Burger Combo", "variations": [{ "externalId": "var-combo", "name": "Regular", "price": { "amount": { "amountMinor": 1200, "currency": "USD" } } }], "modifierGroups": [ { "externalId": "grp-side", "name": "Choose your side", "minSelections": 1, "maxSelections": 1, "options": [ { "externalId": "side-fries", "name": "Fries" }, { "externalId": "side-salad", "name": "Side salad", "modifierGroups": [ { "externalId": "grp-dressing", "name": "Dressing", "minSelections": 1, "maxSelections": 1, "options": [ { "externalId": "drs-ranch", "name": "Ranch" }, { "externalId": "drs-vinaigrette", "name": "Vinaigrette" } ] } ] } ] } ] } ``` Choosing **Side salad** reveals a required **Dressing** choice; choosing **Fries** doesn't. Nest as deep as the menu needs. Order resources currently expose the directly-selected, first-level modifiers on each line item — deeper nested selections aren't expanded into the order resource yet. ## Availability: daily specials A breakfast section that only shows on weekday mornings. Put the window on the category (it narrows everything inside) or on a single item: ```json theme={null} { "externalId": "cat-breakfast", "name": "Breakfast", "availability": { "windows": [ { "dayOfWeek": 1, "startTime": "07:00", "endTime": "11:00" }, { "dayOfWeek": 2, "startTime": "07:00", "endTime": "11:00" }, { "dayOfWeek": 3, "startTime": "07:00", "endTime": "11:00" }, { "dayOfWeek": 4, "startTime": "07:00", "endTime": "11:00" }, { "dayOfWeek": 5, "startTime": "07:00", "endTime": "11:00" } ] }, "items": [{ "externalId": "itm-pancakes", "name": "Pancakes", "variations": [{ "externalId": "var-pancakes", "name": "Regular", "price": { "amount": { "amountMinor": 950, "currency": "USD" } } }] }] } ``` * `dayOfWeek` is `0` (Sunday) through `6` (Saturday); add one window per active day. * `startTime` / `endTime` are local `HH:MM` (24-hour), in the menu's timezone — set the top-level `timezone` (it [defaults to UTC](/developer-api/guides/publish-menu#set-the-timezone-for-availability)). * An object with no `availability` is always available. This is how time-of-day menus work — there's [one menu per location](/developer-api/concepts/the-menu-model#one-menu-per-location), and availability windows carve it up. ## Happy hour: a recurring discount A recurring discount takes three top-level objects working together — what's targeted (a product set), the discount math, and when it's active (the promotion): ```json theme={null} { "productSets": [ { "externalId": "set-drinks", "name": "All drinks", "itemIdsAny": ["itm-latte", "itm-cold-brew"] } ], "discounts": [ { "externalId": "disc-happy-hour", "name": "20% off drinks", "benefitType": "percentage", "percentage": 20, "benefitTargetProductSetId": "set-drinks" } ], "promotions": [ { "externalId": "promo-happy-hour", "name": "Happy hour", "discountId": "disc-happy-hour", "applicationMode": "automatic", "availability": { "windows": [ { "dayOfWeek": 1, "startTime": "16:00", "endTime": "18:00" }, { "dayOfWeek": 2, "startTime": "16:00", "endTime": "18:00" }, { "dayOfWeek": 3, "startTime": "16:00", "endTime": "18:00" }, { "dayOfWeek": 4, "startTime": "16:00", "endTime": "18:00" }, { "dayOfWeek": 5, "startTime": "16:00", "endTime": "18:00" } ] } } ] } ``` * The **product set** says *what* the discount applies to (here, two drink items; use `"allProducts": true` for the whole menu). * The **discount** says *how much* (20% off). Other `benefitType`s include `amount`, `set_price`, `free_item`, and `bxgy`. * The **promotion** ties them together and says *when*: `applicationMode: "automatic"` applies it without a code, and `availability` gives the recurring weekly windows. Use `validFrom` / `validUntil` for a one-off campaign instead. The IDs wiring these together — `discountId`, `benefitTargetProductSetId`, and the `itemIdsAny` members — are the `externalId`s you assigned. Cross-references in a menu always use your IDs, never Maple's. The promotion's `availability` windows use the menu's timezone (set the top-level `timezone`; it defaults to UTC). ## 86 an item Mark something out of stock without restructuring the menu — set `stockStatus` on the item (or variation): ```json theme={null} { "externalId": "itm-latte", "name": "Latte", "stockStatus": "out_of_stock", "variations": [{ "externalId": "var-latte", "name": "Regular", "price": { "amount": { "amountMinor": 450, "currency": "USD" } } }] } ``` `stockStatus` is `in_stock`, `out_of_stock`, or `low_stock`. Omitting it on a re-publish preserves the current value, so a stock update can be a small, targeted publish. ## Combine them These compose. A breakfast category (availability) can hold a build-your-own item (nested modifiers) with a "first topping free" group (`freeSelectionCount`), all while a happy-hour promotion runs on drinks. Publish the whole menu and Maple applies it as one diff — see [Publish a menu](/developer-api/guides/publish-menu). # Publish a menu Source: https://docs.maple.inc/developer-api/guides/publish-menu Send a location’s full menu as one JSON document keyed by your own stable IDs, then read it back. Publishing is a diff, so re-publishing is safe. A location's menu is the catalog customers order from. You publish it as **one JSON document** that describes the whole menu — categories, items, variations, modifiers, and the tax and fee definitions that apply. Maple keys everything off the **external IDs you assign**, so the `menu_entity_id` on every order line item maps straight back to your own catalog. Publishing requires the `menus:write` scope and an **active connection** to the location. Reading requires `menus:read`. See [How Maple works](/developer-api/how-maple-works) for connections. ## The shape of a menu A menu is a tree with shared definitions alongside it: ``` menu ├── categories[] (required) │ └── items[] │ └── variations[] (required: at least one — the price lives here) │ └── modifierGroups[] (inline, or a reference to a shared group) ├── modifierGroups[] (shared definitions, referenced by groupId) ├── taxCategories[] / taxRates[] ├── fees[] └── discounts[] / promotions[] / coupons[] ``` Two rules carry most of the model: * **Every object has an `externalId`** — your stable handle for it. You choose these; Maple never changes them. Re-publishing with the same `externalId` updates the same object. The response also mints Maple IDs (`item_…`, `var_…`, `ctg_…`) for reference, but you address objects by your `externalId`. * **The price lives on the variation.** Even a simple item has at least one variation (call it "Regular"). All prices are **integer minor units** — `450` is \$4.50. ## A minimal menu The smallest valid document is a currency and one category containing one item with one variation: ```bash theme={null} curl -X POST $MAPLE_BASE/locations/{locationId}/menu \ -H "Authorization: Bearer $MAPLE_KEY" \ -H "Content-Type: application/json" \ -d '{ "currency": "USD", "categories": [ { "externalId": "cat-drinks", "name": "Drinks", "items": [ { "externalId": "itm-latte", "name": "Latte", "variations": [ { "externalId": "var-latte-reg", "name": "Regular", "price": { "amount": { "amountMinor": 450, "currency": "USD" } } } ] } ] } ] }' ``` A successful publish returns the resulting menu with every collection materialized and Maple IDs filled in. The `externalId`s you sent are echoed back unchanged. ## Add shared modifiers Define a modifier group once at the top level and reference it by `groupId` wherever it applies — so "Milk options" stays in one place across every drink: ```json theme={null} { "currency": "USD", "modifierGroups": [ { "externalId": "grp-milk", "name": "Milk", "minSelections": 0, "maxSelections": 1, "options": [ { "externalId": "mod-whole", "name": "Whole milk" }, { "externalId": "mod-oat", "name": "Oat milk", "price": { "amount": { "amountMinor": 75, "currency": "USD" } } } ] } ], "categories": [ { "externalId": "cat-drinks", "name": "Drinks", "items": [ { "externalId": "itm-latte", "name": "Latte", "variations": [{ "externalId": "var-latte-reg", "name": "Regular", "price": { "amount": { "amountMinor": 450, "currency": "USD" } } }], "modifierGroups": [{ "groupId": "grp-milk" }] } ] } ] } ``` A modifier group entry is either an **inline definition** (carries `name` and `options`) or a **reference** (`{ "groupId": "grp-milk" }`). Don't mix the two shapes in one entry — a payload that does is rejected rather than silently truncated. Items, variations, and individual options can each carry modifier groups, which lets you nest options where the menu calls for it. Tax categories and rates, fees (like a bottle deposit), discounts, promotions, and coupons are all optional top-level collections, each addressed by its own `externalId` and attached to items by ID (`taxCategoryId`, `feeIds`, and so on). The [endpoint reference](/developer-api/api-reference) documents every field. ## Publishing semantics Every publish sends the **entire menu** as its desired state. Maple diffs it against the current menu (keyed by `externalId`) and applies the result as a new version. A few rules follow from that: * **The document is the whole menu.** Whatever you send becomes the menu. An object you published before but leave out of a later publish is **removed** — to keep something, include it every time. * **`stockStatus` is the exception.** It's a field-level value: leaving it off an object you *do* include preserves that object's current stock (new objects default to `in_stock`). So 86-ing an item is still a complete publish that includes every object — you just set one field. * **Identity is your `externalId`.** The same `externalId` updates the same object across publishes; a new one creates a new object. Use IDs that are stable in your system (a SKU or primary key), not display names. * **Order is preserved.** Categories, items, variations, and options appear in the order you send them. * **Validation is all-or-nothing.** If anything is invalid you get a `400` listing every issue, and the menu is left exactly as it was. Fix them all and re-send. * **Identical re-publishes are no-ops.** Sending the same document changes nothing and creates no churn, so you can safely publish on every menu change. * **Each change is versioned.** A content change cuts a new version; the location always serves the current one. Because the document is the full desired state, the simplest integration re-publishes the entire menu whenever your source changes. You never compute diffs — Maple does. ### Set the timezone for availability Availability windows (dayparting and happy hours) are evaluated in the **menu's timezone**. Set it with the top-level `timezone` field — an IANA name like `America/New_York`: ```json theme={null} { "currency": "USD", "timezone": "America/New_York", "categories": [ /* … */ ] } ``` If you omit it, the menu's timezone defaults to **UTC**, which is almost never right for time-based rules. The timezone is established on your **first** publish, so set it correctly up front. ## Read it back ```bash theme={null} curl $MAPLE_BASE/locations/{locationId}/menu \ -H "Authorization: Bearer $MAPLE_KEY" ``` Returns the current published menu — categories, items, and variations with prices, shared modifier groups, and tax, fee, and discount definitions — every object echoing the `externalId` you published it under. A location with no published menu returns a `404`. ## Know when a publish lands Subscribe to the menu sync events to be notified as a published menu propagates: | Event | Meaning | | --------------------- | ----------------------------------- | | `menu.sync.completed` | A menu sync finished for a location | | `menu.sync.failed` | A menu sync failed for a location | See [Webhooks](/developer-api/concepts/webhooks) to subscribe and verify these. ## Next Order line items reference your menu by the `externalId` you assign. Every field on every menu object, in the endpoint reference. # Receive and decide orders Source: https://docs.maple.inc/developer-api/guides/receive-orders Build the order loop: connect a location, subscribe to webhooks, verify deliveries, and drive each order with accept, deny, ready, and complete calls. This is the core of a Maple integration. When a customer orders at a location you're connected to, Maple pushes the order to your webhook; you decide whether to fulfill it and report progress as it moves. **None of it involves payments** — Maple owns that. A working ordering integration is two pieces of work: | # | What you build | Typical effort | | - | ----------------------------------------------------------------- | -------------- | | 1 | Receive orders — one webhook endpoint with signature verification | \~1–2 days | | 2 | Decide orders — accept / deny / status calls back to Maple | \~1–2 days | If you haven't yet, skim [How Maple works](/developer-api/how-maple-works) for the object model, and run the [Quickstart](/developer-api/quickstart) to get a key and connect a test location. ## Step 1 — Connect a location Orders route to you only once your app is a location's connected receiver: ```bash theme={null} curl -X POST $MAPLE_BASE/locations/{locationId}/connection \ -H "Authorization: Bearer $MAPLE_KEY" ``` Connections are exclusive per environment — if another app already holds the location you get a `409`. `GET` and `DELETE` on the same path inspect and remove your connection. ## Step 2 — Subscribe to webhooks Register an HTTPS endpoint and the event types you want. The full catalog is at `GET /v1/webhook_event_types`; for the order loop you'll typically want these: ```bash theme={null} curl -X POST $MAPLE_BASE/webhook_subscriptions \ -H "Authorization: Bearer $MAPLE_KEY" \ -H "Content-Type: application/json" \ -d '{ "notification_url": "https://your-app.example.com/maple/webhooks", "event_types": ["order.notification", "order.validation_requested", "order.cancelled"] }' ``` The response carries a **one-time signing secret** (`mwhsec_…`). Store it; it is never shown again. The URL must be public HTTPS — private and internal addresses are rejected. These are the order events. The catalog also includes `order.created`, `order.paid`, `store.provisioned`, `store.deprovisioned`, `store.status.changed`, and the menu sync events. Subscribe only to what you act on. See the full list and payloads in [Webhooks](/developer-api/concepts/webhooks#event-types). ## Step 3 — Verify every delivery Each delivery is a Stripe-style envelope: ```json theme={null} { "object": "event", "id": "evt_...", "type": "order.notification", "created": 1765432100, "data": { "order_id": "ord_...", "location_id": "str_...", "...": "the order content — see Step 4" } } ``` Deliveries carry two headers: `maple-webhook-id` (the event id) and `maple-webhook-signature` in the form `t=,v1=`. The signed string is `{timestamp}.{subscription_id}.{notification_url}.{raw_body}`. Verify it against the raw, unparsed body: ```ts theme={null} import { createHmac, timingSafeEqual } from 'node:crypto'; function verifyMapleWebhook(params: { signatureHeader: string; // maple-webhook-signature subscriptionId: string; // your subscription id (dws_…) notificationUrl: string; // the exact URL you registered rawBody: string; // the unparsed request body signingSecret: string; // mwhsec_… toleranceSeconds?: number; // default 300 }): boolean { const parts = Object.fromEntries(params.signatureHeader.split(',').map((p) => p.split('='))); const timestamp = Number(parts.t); const provided = parts.v1 ?? ''; // Reject stale deliveries to prevent replay. const skew = Math.abs(Math.floor(Date.now() / 1000) - timestamp); if (!Number.isFinite(timestamp) || skew > (params.toleranceSeconds ?? 300)) return false; const signed = `${timestamp}.${params.subscriptionId}.${params.notificationUrl}.${params.rawBody}`; const expected = createHmac('sha256', params.signingSecret).update(signed).digest('hex'); return expected.length === provided.length && timingSafeEqual(Buffer.from(expected), Buffer.from(provided)); } ``` The check above rejects stale timestamps (older than \~5 minutes) to prevent replay. Beyond that, **dedupe on the envelope `id`** — delivery is at-least-once. The full reliability contract, including the retry schedule and the ledger, is in [Webhooks](/developer-api/concepts/webhooks). ### Catching up after downtime When your receiver was unavailable — the local software was off, or the network was down — reconcile like this: 1. Call `GET /v1/orders?since=&limit=100` with your last successful checkpoint (exclusive, ISO 8601 UTC). With `since`, results are oldest first and `has_more` indicates another page. 2. While `has_more` is true, repeat the request with `starting_after` set to the last order id from the previous page. Continue until the backlog is drained, then advance your checkpoint. 3. Call `POST /v1/orders/{orderId}/resend` when you need Maple to publish a fresh `order.notification` for one live order that missed its webhook. It requires the `webhooks:write` scope, creates a new signed, retried delivery, and does not change the order's state. Terminal orders (`REJECTED`, `CUSTOMER_CANCELLED`, or `STORE_CANCELLED`) cannot be resent or revived and return `400`; reconcile them with `GET /v1/orders?since=...` and `GET /v1/orders/{orderId}`. 4. Use the [event ledger](/developer-api/concepts/webhooks#the-event-ledger) instead of `resend` when preserving the original event identity matters. Waiting it out also works for a short outage: the [retry schedule](/developer-api/concepts/webhooks#retries-and-auto-disable) redelivers a failed event over roughly 10 hours before it counts as fully failed. Before you have real traffic, `POST /v1/webhook_subscriptions/{id}/test` sends a signed `webhook.test` event so you can prove your handler verifies and responds correctly. ## Step 4 — Read the order The `order.notification` payload's `data` is the **order's content** — its IDs, customer, line items, and totals — so you can start fulfilling straight from the webhook without another call. It follows the `GET /v1/orders/{orderId}` shape, but omits the live `status` and `payment`. Fetch the order resource any time for the authoritative current state, including `status` and `payment`: ```json theme={null} { "object": "order", "id": "ord_...", "livemode": false, "created": 1765432100, "status": "PENDING", "fulfillment_type": "delivery", "scheduled_for": null, "location_id": "str_...", "delivery_address": { "street": "123 Main Street", "unit": "Apt 4B", "city": "New York", "state": "NY", "zip": "10001", "notes": "Leave at the side door" }, "customer": { "name": "Alex", "phone": "+14155551234", "phone_last_four": "1234" }, "line_items": [ { "name": "Latte", "menu_entity_id": "itm-latte", "quantity": 1, "base_price": 450, "tax": 36, "modifiers": [{ "name": "Oat milk", "menu_entity_id": "mod-oat", "quantity": 1, "price": 75 }] } ], "totals": { "currency": "USD", "subtotal": 525, "tax": 42, "surcharge": 0, "tip": 0, "delivery_fee": 599, "delivery_tip": 0, "total": 1166 }, "external_id": null, "payment": { "provider": "stripe", "status": "unpaid", "payment_link_url": "https://..." } } ``` A few things to internalize: * **Money is integer USD cents.** `450` is \$4.50. Never parse it as a float. Every amount in `totals` and on line items follows this convention. * **Totals are precomputed.** `totals.total` is authoritative. You do not re-price anything. * **Line items reference your menu** by `menu_entity_id`, whose value is the `externalId` you published for that item. Publish a menu first and these line up with your own catalog. (Menu payloads are camelCase; order and webhook payloads are snake\_case — see [Conventions](/developer-api/api-reference#resource-conventions).) * **Modifiers are the directly-selected, first-level options.** Deeper nested modifier selections aren't expanded into the order resource in v1. * **Customer data is intentionally minimal.** You get the customer's name and phone number (`phone` in E.164 format, plus `phone_last_four` for display). Delivery orders also include `delivery_address` with the street, unit, city, state, ZIP code, and delivery instructions; it is `null` for pickup orders or when Maple has no stored address. All six address keys are present whenever the block is populated. * **Check `scheduled_for` before firing the ticket.** It's `null` for ASAP orders. When set (ISO 8601, UTC), the customer chose that pickup/delivery time — you receive the order immediately, so schedule preparation for `scheduled_for`, not on receipt. ## Step 5 — Decide and report progress Respond through the decision endpoints as the order moves. None take a body unless noted: | Call | When | | ------------------------------------ | -------------------------------------------------------------- | | `POST /v1/orders/{orderId}/accept` | You can fulfill it | | `POST /v1/orders/{orderId}/deny` | You can't — optional `{ "reason": "…" }` | | `POST /v1/orders/{orderId}/ready` | Ready for pickup or courier handoff | | `POST /v1/orders/{orderId}/complete` | Fulfilled | | `POST /v1/orders/{orderId}/cancel` | You must cancel after accepting — optional `{ "reason": "…" }` | | `POST /v1/orders/{orderId}/status` | Granular transition (see below) | ```bash theme={null} curl -X POST $MAPLE_BASE/orders/{orderId}/accept \ -H "Authorization: Bearer $MAPLE_KEY" ``` ```json Response theme={null} { "object": "order_decision", "order_id": "ord_...", "decision": "accept", "status": "received" } ``` If you prefer one endpoint, `POST /v1/orders/{orderId}/status` takes an explicit transition: ```json theme={null} { "status": "ACCEPTED" } ``` Valid values: `ACCEPTED`, `READY`, `IN_DELIVERY`, `FULFILLED`, `REJECTED`, `STORE_CANCELLED`. For what each status means and the legal transitions between them, see the [Order lifecycle](/developer-api/concepts/order-lifecycle). **Decision calls are replay-safe.** Repeating one returns `{ "status": "received" }` with no double side effects, so retrying on a network blip is always safe. See [Idempotency and replay safety](/developer-api/concepts/idempotency). ## Optional — pre-validate orders Pre-validation is **opt-in, and you turn it on by subscribing to `order.validation_requested`**: * **If you don't subscribe**, there's no validation step. Maple sends `order.notification` directly, and your accept/deny is the only gate. * **If you subscribe**, Maple asks you to confirm each order is fulfillable (item availability, pricing feasibility, POS injectability) *before* it sends the notification, and waits for your answer. Opting in is therefore a commitment: an order you don't validate in time is rejected (see below). That's the whole mechanism — the subscription is the switch. When subscribed, respond to each `order.validation_requested` with a result: ```bash theme={null} curl -X POST $MAPLE_BASE/orders/{orderId}/validation_result \ -H "Authorization: Bearer $MAPLE_KEY" \ -H "Content-Type: application/json" \ -d '{ "status": "valid", "partner_reference": "pos_quote_123" }' ``` To block the order instead: ```json theme={null} { "status": "invalid", "reason": { "code": "ITEM_AVAILABILITY", "explanation": "86'd", "item_external_ids": ["itm-latte"] } } ``` A `valid` result lets the order proceed to notification; `invalid` blocks it before the customer is charged. You have about **5 minutes** to respond before a request expires (the resource carries `expires_at`, \~300 seconds out). If it expires, Maple requests validation **once more**; if that second request also goes unanswered, the order is rejected without a notification — so only subscribe once your handler reliably answers in time. It's the same availability check you'd run at accept time, only earlier, so customers don't pay for something you can't make. ## What "done" looks like | You build | You get | | ------------------------------------------------------ | ------------------------------------------------- | | One webhook handler that verifies, dedupes, and routes | Real-time orders pushed with precomputed totals | | Accept / deny / ready / complete / status calls | Customers see live order progress | | *(Optional)* validation responses | Bad orders blocked before the customer is charged | One webhook and a handful of decision calls. Payments and pricing stay on our side, and the Maple team is available throughout your build. ## Next Make `menu_entity_id` on every line item map to your own catalog. Delivery guarantees, retries, the event ledger, and replay. # How Maple works Source: https://docs.maple.inc/developer-api/how-maple-works The objects and relationships behind every integration — apps, locations, connections, and the division of responsibility between you and Maple. Before you write code, it helps to hold the whole model in your head. There are only a handful of objects, and they fit together in one direction. ## The objects Your integration. Maple creates it during onboarding and issues its credentials. An app operates in **test** or **live**, never both at once — the credential you use selects which. A single restaurant — the unit the Developer API works with (ID `str_…`). A merchant **grants** your app access to a location; that grant lets you read it. Locations have a `status` (`active`, `inactive`, `paused`) you should respect. Locations sit under merchants and organizations — see [Organizations, merchants, and locations](/developer-api/concepts/entities). Connecting to a granted location makes your app its **order receiver**. Orders route to you only after a connection exists. A location can be connected to exactly one app per environment. A customer's order at a connected location, with line items, totals (computed by Maple), and a payment object. You drive it through its lifecycle with decision calls. The catalog for a location — categories, items, variations, modifiers, and tax and fee definitions — published as one JSON document keyed by your own external IDs. An HTTPS endpoint plus the event types you want. Maple signs and delivers events to it, and keeps a ledger you can replay from. ## How they connect ```mermaid theme={null} flowchart LR App[Your developer app] -- granted --> Loc[Location] App -- connection --> Loc Loc -- emits --> Order[Order] App -- publishes --> Menu[Menu] Order -- order.notification --> Hook[Your webhook endpoint] Hook -- accept / deny / ready / complete --> Order ``` A merchant grants you a location → you connect to it → orders from that location are pushed to your webhook → you decide each order. In parallel, you publish the menu those orders are built from. ## Who owns what This is the most important thing to understand, and the part most restaurant integrations get wrong. Maple owns the parts that carry risk: | Maple owns | You own | | ------------------------------------------------------------ | ----------------------------------------------------- | | The customer payment lifecycle (Stripe-backed payment links) | Receiving orders and deciding them | | Every customer-facing total, tax, and fee calculation | Reflecting order state back (accept, ready, complete) | | Card data and PCI scope | Publishing an accurate menu | | Delivering, retrying, and signing webhooks | Verifying signatures and deduping events | You never compute a price, touch a card, or build a payment flow. Maple hands you an order with `totals` already final and a `payment` object you can read but don't manage. Treat Maple's totals as authoritative. Your job at order time is to decide whether you can fulfill the order — not to re-price it. ## The order loop, end to end 1. A customer orders at a connected location. 2. *(Optional)* Maple sends `order.validation_requested` and waits for you to confirm the order is fulfillable. See [validating orders](/developer-api/guides/receive-orders#optional--pre-validate-orders). 3. Maple sends `order.notification` with the full order. 4. You **accept** or **deny** it. 5. You report progress — **ready**, then **complete** — or **cancel** if you must after accepting. 6. You receive `order.cancelled` if the customer or store cancels. Every decision call is replay-safe, so retries are harmless. The full sequence lives in [Receive and decide orders](/developer-api/guides/receive-orders). ## Environments Maple runs two isolated environments, each with its own base URL: * **Sandbox** — `https://api.staging.maple.inc/v1`, with your `mpk_test_…` key. For development and testing. * **Production** — `https://api.maple.inc/v1`, with your `mpk_live_…` key. Live traffic. You build and verify everything in the sandbox against isolated data, then point the same code at production once your integration is approved. The two never see each other's data. More in [Environments and test mode](/developer-api/concepts/environments). ## Next Make the first calls yourself. API keys, environments, and scopes in detail. # Developer API Source: https://docs.maple.inc/developer-api/overview Connect your POS or platform to Maple — receive and decide orders, publish menus, and subscribe to signed webhooks. The Maple Developer API connects your POS or platform to Maple. You receive orders the moment a customer places them, decide whether to accept them, publish the menus customers order from, and keep everything in sync through signed webhooks. There is no SDK to install, and **there is no payment processing to build** — Maple owns the entire customer payment lifecycle and hands you orders with totals already calculated. Most partners reach a working test integration in a few days. Make your first authenticated call in a few minutes. Start here. The mental model: apps, locations, connections, and who owns what. ## Start with the job you're doing Get `order.notification` webhooks and drive each order with accept, deny, ready, and complete calls. Send a location's full menu as one JSON document keyed by your own stable IDs, and read it back. Verify HMAC signatures, dedupe deliveries, and replay from the event ledger. Request and response schemas for auth, locations, connections, menu, orders, and webhooks. ## What you never have to build Restaurant integrations are usually painful because you inherit problems that aren't yours. With Maple, you don't: * **No payment integration.** Maple creates and owns the payment link. You never touch a card or carry PCI scope. * **No pricing engine.** Maple computes every customer-facing total. You read integer cents. * **No polling.** Orders are pushed to your webhook; a ledger and replay endpoints cover recovery. * **No SDK required.** It's a REST API you can call from any language. * **No guessing in production.** You build against isolated test data first; live access is enabled once your integration is approved. ## The shape of the API Every request carries a `Bearer` credential. You develop against the sandbox and move to production by changing the base URL and credential — nothing else: ```bash theme={null} # Sandbox — build and test here curl https://api.staging.maple.inc/v1/me \ -H "Authorization: Bearer mpk_test_..." ``` * **Two environments:** the sandbox at `https://api.staging.maple.inc/v1` for development, and production at `https://api.maple.inc/v1`. They're fully isolated. See [Environments](/developer-api/concepts/environments). * **API key auth:** send your key (`mpk_test_…` / `mpk_live_…`) as a Bearer token. See [Authentication](/developer-api/concepts/authentication). * **Scoped access:** your app holds only the permissions it needs (`orders:read`, `menus:write`, `webhooks:write`, and so on). * **Predictable resources:** opaque IDs, money as integer USD cents, Stripe-style event envelopes, and consistent error bodies. Getting started begins with onboarding — the Maple team creates your developer app and issues your test credentials. [Contact us](https://maple.inc/get-started) to begin, then follow the [Quickstart](/developer-api/quickstart). # Postman collection Source: https://docs.maple.inc/developer-api/postman A ready-to-run Postman collection for the whole Developer API, with auth and request chaining wired up. The Postman collection covers every Developer API endpoint — status and auth, the OAuth flows, locations and connections, menu read/publish, the full order loop, and webhooks. It ships with helper scripts so you can run a flow end to end without copy-pasting ids between requests. ## Download All endpoints, example bodies, and scripts. Points at `api.staging.maple.inc`; use your `mpk_test_…` key. Points at `api.maple.inc`; use your `mpk_live_…` key. ## Get set up In Postman, **Import** the collection file, then import the **Staging** (or **Production**) environment file. Select that environment in the top-right environment selector. Open the environment and paste your key into `apiKey` — `mpk_test_…` for staging, `mpk_live_…` for production. That's the only value you need to set for API-key auth. Requests send `Authorization: Bearer {{bearerToken}}`. When `bearerToken` is empty it automatically falls back to your `apiKey`, so setting `apiKey` is enough. Run **Status & Auth → Current app (/me)**. A `200` with your app name, environment, and scopes means you're ready. Run **Locations & Connections → List locations**, then **Get location** / **Create connection** below it — the list request saves the first `locationId` into the environment, so the requests under it just work. The same chaining captures `orderId`, `subscriptionId`, and `eventId`. ## What the scripts do * **Auth fallback** — a collection pre-request uses your `apiKey` as the bearer token unless an explicit `bearerToken` is set. * **Id chaining** — list requests save the first returned id (`locationId`, `orderId`, `subscriptionId`, `eventId`) to the environment for the requests that need it. * **Webhook secret capture** — *Create webhook subscription* stores the one-time `signing_secret` into `signingSecret` (store it securely; it's shown only once). * **OAuth (optional)** — the **OAuth** folder exchanges client credentials for an access token and switches `bearerToken` to it automatically. It also includes a PKCE generator and the authorization-code exchange. Clear `bearerToken` to switch back to your API key. Money fields are integer minor units (cents). The publish-menu request includes a complete example document you can adapt. For field-by-field detail, see the [API reference](/developer-api/api-reference) and [The menu model](/developer-api/concepts/the-menu-model). # Quickstart Source: https://docs.maple.inc/developer-api/quickstart From a test API key to a verified webhook delivery in about ten minutes. By the end of this page you'll have made your first authenticated call, listed the locations your app can reach, and received a real signed webhook at your own endpoint — all in test mode, against isolated data you can't break. ## Before you begin You need a **sandbox API key** (`mpk_test_…`). The Maple team issues one when they create your developer app during onboarding. If you don't have one yet, [contact us](https://maple.inc/get-started) — it takes us a few minutes. That's the only prerequisite. There's no SDK to install; every example here is plain `curl` you can paste into a terminal. You'll work against the **sandbox** the whole way — isolated data you can't break. (Production lives at `https://api.maple.inc/v1`; see [Environments](/developer-api/concepts/environments).) Keep your key and the sandbox base URL in environment variables so you can copy the examples verbatim: ```bash theme={null} export MAPLE_KEY="mpk_test_..." export MAPLE_BASE="https://api.staging.maple.inc/v1" ``` `/ping` needs no credential. A clean response means your network can reach Maple. ```bash theme={null} curl $MAPLE_BASE/ping ``` ```json Response theme={null} { "object": "developer_api_status", "status": "ok", "version": "..." } ``` `GET /v1/me` echoes back the app your credential belongs to, the environment it operates in, and the scopes it holds. It's the fastest way to confirm a key works. ```bash theme={null} curl $MAPLE_BASE/me \ -H "Authorization: Bearer $MAPLE_KEY" ``` ```json Response theme={null} { "object": "developer_app", "id": "dap_...", "name": "Your Integration", "environment": "test", "scopes": ["locations:read", "connections:write", "orders:read", "orders:write", "webhooks:write"] } ``` `environment` reads `test`. A test key can only ever see test data — nothing you do here touches a live merchant. If you get a `401`, the key is missing, malformed, or inactive. See [Errors](/developer-api/concepts/errors). Each restaurant your app integrates is a **location** a merchant has granted you access to. List the ones you can see: ```bash theme={null} curl $MAPLE_BASE/locations \ -H "Authorization: Bearer $MAPLE_KEY" ``` ```json Response theme={null} { "object": "list", "data": [ { "object": "location", "id": "str_test_123", "name": "Maple Test Kitchen", "status": "active", "timezone": "America/New_York", "...": "..." } ] } ``` During onboarding we grant your test app at least one test location to build against. Note its `id`. A grant lets you *see* a location. A **connection** makes your app its order receiver — orders only route to you after this call. ```bash theme={null} curl -X POST $MAPLE_BASE/locations/str_test_123/connection \ -H "Authorization: Bearer $MAPLE_KEY" ``` ```json Response theme={null} { "object": "connection", "location_id": "str_test_123", "status": "active", "...": "..." } ``` Connections are exclusive per environment: if another app already holds the location, you get a `409`. Read [How Maple works](/developer-api/how-maple-works) for the full grant-versus-connection model. Register an HTTPS endpoint you control. (For local testing, a tunnel such as ngrok or Cloudflare Tunnel gives you a public URL.) ```bash theme={null} curl -X POST $MAPLE_BASE/webhook_subscriptions \ -H "Authorization: Bearer $MAPLE_KEY" \ -H "Content-Type: application/json" \ -d '{ "notification_url": "https://your-app.example.com/maple/webhooks", "event_types": ["order.notification"] }' ``` The response includes a **one-time signing secret** (`mwhsec_…`). Store it now — it is never shown again. ```json Response theme={null} { "object": "webhook_subscription.created", "subscription": { "object": "webhook_subscription", "id": "dws_...", "status": "enabled", "...": "..." }, "signing_secret": "mwhsec_..." } ``` Now fire a synthetic delivery to that endpoint to confirm it's wired up: ```bash theme={null} curl -X POST $MAPLE_BASE/webhook_subscriptions/dws_.../test \ -H "Authorization: Bearer $MAPLE_KEY" ``` ```json Response theme={null} { "object": "webhook_test_result", "event_id": "evt_...", "delivered": true, "response_status": 200 } ``` `delivered: true` with a `2xx` `response_status` means Maple reached your endpoint and it accepted the event. You're receiving webhooks. ## You just did the whole loop in miniature Authenticate, find a location, connect to it, and receive a signed event — that's the spine of every Maple integration. Everything else is filling it in. ## Where to go next Verify webhook signatures and drive real orders with accept / deny / ready / complete. Push a location's menu so the items in your orders map to your own IDs. Signature verification, delivery guarantees, retries, and replay. API keys, environments, and scopes. # Webhook events Source: https://docs.maple.inc/developer-api/webhook-events The catalog of webhook event types and the payload each one carries. Payloads here are documented from what Maple emits, but they aren't formally schema-typed yet — new fields may be added. Validate defensively (ignore unknown fields), and treat `GET /v1/orders/{orderId}` as the authoritative source for an order's current state. The live list of event types is always at `GET /v1/webhook_event_types`. Every webhook is delivered in the same [signed envelope](/developer-api/concepts/webhooks#the-event-envelope); only the `data` differs by `type`. This page documents each event type. For signing, delivery, retries, and replay, see [Webhooks](/developer-api/concepts/webhooks). ## Order events Order webhooks come in two kinds, and knowing which is which is the key to using them well: * **`order.notification` is the event you fulfill against.** It hands you the order's content to act on, fires once at handoff, and its delivery is treated as critical. Build your accept / deny / ready / complete loop on it. * **`order.created`, `order.paid`, and `order.cancelled` are lifecycle events.** Each reports one moment in the order's life with summary data, for awareness and reconciliation. Because `order.notification` fires only once and never updates, these are how you learn about things that happen before or after that snapshot — most importantly a cancellation, or payment settling later. For the order in which these fire across one order's life, see [When the webhooks fire](/developer-api/concepts/order-lifecycle#when-the-webhooks-fire). | Type | Fires when | Subscribe to it to… | `data` | | ---------------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------- | | `order.validation_requested` | Before notification — Maple asks you to confirm the order is fulfillable (only if you subscribe) | Pre-validate availability and pricing before the customer is charged | Full order content (same shape as `order.notification`) | | `order.notification` | The order is handed to you to fulfill, after validation and payment gating | **Receive and fulfill orders** — the core of an integration | Full order content (see below) | | `order.created` | An order is created — earlier than, and thinner than, the notification | Mirror new orders for analytics; catch orders that never reach you (e.g. rejected at validation) | `order_id`, `location_id`, `status`, `total`, `items`, `created_at` | | `order.paid` | Payment settles — which can be *after* the handoff (pay-in-store, pay-by-link) | Reconcile payment without polling | `order_id`, `location_id`, `status`, `amount`, `payment_method`, `payment_source` | | `order.cancelled` | The customer or store cancels — often *after* you've been notified | Stop fulfilling a cancelled order | `order_id`, `location_id`, `status`, `reason` | ### Which order events should I subscribe to? * **Fulfilling orders (a POS):** `order.notification` and `order.cancelled` — receive orders, and stop when one is cancelled. Add `order.validation_requested` if you pre-validate. * **Reporting or reconciliation (an OMS, dashboard, analytics):** also `order.created` and `order.paid`, to mirror the order and payment lifecycle. ### The `order.notification` payload `order.notification` (and `order.validation_requested`) carry the order's content in `data` — enough to start fulfilling, following the `GET /v1/orders/{orderId}` shape: ```json theme={null} { "order_id": "ord_...", "location_id": "str_...", "fulfillment_type": "delivery", "scheduled_for": null, "delivery_address": { "street": "123 Main Street", "unit": "Apt 4B", "city": "New York", "state": "NY", "zip": "10001", "notes": "Leave at the side door" }, "customer": { "name": "Alex", "phone": "+14155551234", "phone_last_four": "1234" }, "line_items": [ { "name": "Latte", "menu_entity_id": "itm-latte", "quantity": 1, "base_price": 450, "modifiers": [{ "name": "Oat milk", "menu_entity_id": "mod-oat", "quantity": 1, "price": 75 }] } ], "totals": { "currency": "USD", "subtotal": 525, "tax": 42, "surcharge": 0, "tip": 0, "delivery_fee": 599, "delivery_tip": 0, "total": 1166 } } ``` This is the order's **content**, not its live state — it has no `status` or `payment`. For the authoritative current state (status, payment, per-item tax, timestamps), fetch [`GET /v1/orders/{orderId}`](/developer-api/concepts/order-lifecycle). The lifecycle events carry only the summary fields listed above. `scheduled_for` is `null` for ASAP orders. When set (ISO 8601, UTC), the customer chose that pickup/delivery time — the notification still arrives immediately, so prepare the order for `scheduled_for`, not on receipt. `delivery_address` is `null` for pickup orders and for delivery orders without a stored address. When present, all six keys are included; `notes` contains the delivery instructions and `unit` or `notes` may be `null`. ### Not a status feed Maple does **not** emit a webhook for every status transition. The transitions you drive yourself (`accept`, `ready`, `complete`) aren't echoed back, and there's no event for reaching `IN_DELIVERY` or for payment moving to `refunded` / `voided` / `failed`. Read the order resource for current state — see the [Order lifecycle](/developer-api/concepts/order-lifecycle#webhooks-dont-track-every-transition). ## Location (store) events These track your access to a location — the [connection lifecycle](/developer-api/concepts/entities#the-connection-lifecycle): | Type | When it fires | `data` (indicative) | | ---------------------- | ------------------------------------------------------- | ------------------------------------------------------ | | `store.provisioned` | A merchant granted your app access to a location | `location_id` | | `store.deprovisioned` | A grant was revoked; you've lost access to the location | `location_id` | | `store.status.changed` | Your connection to a location changed | `location_id`, `status` (`connected` / `disconnected`) | ## Menu events | Type | When it fires | `data` (indicative) | | --------------------- | ------------------------------------ | ------------------- | | `menu.sync.completed` | A menu sync completed for a location | `location_id` | | `menu.sync.failed` | A menu sync failed for a location | `location_id` | See [Publish a menu](/developer-api/guides/publish-menu). ## Test event `webhook.test` is delivered on demand by `POST /v1/webhook_subscriptions/{id}/test`. Use it to verify your handler before any real traffic. It is never emitted by real activity. # Going Live Source: https://docs.maple.inc/going-live Test your agent, then switch on call forwarding to launch Maple. ### **Test Your Agent Before Going Live** Once you've reviewed your menu, set your menu hours, and built out your knowledge base, it's time to test your agent before going live. We recommend calling your **Maple agent number** directly (found in the AI Agents tab) and placing a test order as if you were a real customer. Talk to the agent, place an order, and confirm it prints correctly in your kitchen. ⚠️ **Important:** Maple does not have a separate test environment — test orders behave exactly like real orders and **will print in your kitchen.** To avoid preparing unnecessary food in your kitchen, use **"Test"** as the customer name when placing test orders so your staff knows to ignore them. Once everything feels right and you're happy with how your agent sounds and performs, you're ready to go live. *** ### **Enabling & Disabling Call Forwarding** Call forwarding is what routes your restaurant's main phone line to your Maple agent. This is done directly from your restaurant's phone — Maple does not have access to your line.\\ **To enable call forwarding (go live):** 1. Pick up your restaurant's main phone 2. Dial **\*72** followed by your Maple agent number (no spaces) * Example: `*729064012333` 3. Wait for a confirmation tone 4. Hang up — calls will now route to Maple ✅ **To disable call forwarding (turn Maple off):** 1. Pick up your restaurant's main phone 2. Dial **\*73** 3. Wait for a confirmation tone 4. Hang up — calls return to your normal line ✅ **Carrier variations:** The exact steps may vary depending on your phone carrier. If `*72` doesn't work, contact your carrier and let them know you're trying to forward to a hosted VoIP number. For VoIP or Google Voice systems, forwarding is managed through your provider's admin panel rather than star codes. # Introduction Source: https://docs.maple.inc/index Welcome to the Maple documentation Maple is voice AI for restaurants. We answer calls, take orders, manage bookings, and help customers 24/7—so you can focus on running your business. [Learn more about Maple →](https://maple.inc) ## What can Maple do for you? Take orders over the phone and see them right away in your POS. Answer common questions and get more customers through the door. Handle table reservations through natural conversation via OpenTable. Monitor call volume, order trends, and customer insights from your dashboard. ## Let us handle the phones Maple doesn't need you to manage another tablet or learn about AI. We learn from your calls, improving over time to tune to your business. Our state-of-the-art AI is an expert at conflict resolution, upselling, and managing customer relationships. ## Get started Get your Maple voice AI up and running in 15 minutes. Complete your agent setup and get ready to go live. A complete walkthrough of your Maple dashboard — what's where and how to use it. Support resources, contact options, and how to handle urgent issues.\\ ## Building an integration? If you're a POS or platform partner connecting your system to Maple, head to the Developer API. Receive and decide orders, publish menus, and subscribe to signed webhooks over plain JSON and HTTPS. From a test key to a verified webhook delivery in about ten minutes. # Need Help? Source: https://docs.maple.inc/need-help **Support resources, contact options, and how to handle urgent issues.** *** ### **Contacting Support** We're here to help! Here's how to reach us: * **Email:** [hello@maple.inc](mailto:hello@maple.inc) * **Text or call:** +1 (929) 543-0229 * **In-app chat:** Click the chat bubble in the bottom right corner of your dashboard * **Help Center:** [docs.maple.inc](https://docs.maple.inc) **Live support hours:** Monday–Friday, 9 AM – 6 PM EST While we don't offer 24/7 live support, we always aim to respond to all support questions **within 24 hours** — and often much sooner.  If you reach out outside of business hours, leave us a voicemail or send a message with a description of your issue and the steps you've already taken, and we'll get back to you as soon as possible. *** ### **Urgent Issues — How to Pause or Adjust Your Agent** If something isn't working as expected and you need to act quickly — like orders printing incorrectly, the agent behaving unexpectedly, or any other urgent issue — you have a couple of options to get things under control. ### \*\*Option 1Y \*\* The quickest way to pause Maple entirely is to disable call forwarding directly from your restaurant's main phone: 1. Pick up your restaurant's main phone 2. Dial **\*73** 3. Wait for a confirmation tone and hang up Your calls will immediately return to your normal phone line as if Maple was never there. When you're ready to turn Maple back on, just dial **\*72** followed by your Maple agent number. ### **Option 2 — Adjust Your Agent Without Turning It Off** If you'd prefer to keep Maple answering calls but need to limit what it does, you can make quick adjustments directly from your dashboard under **AI Agents:** **1. Enable Ring Staff First:**  Go to **AI Agents → Call Handling → Ring Staff First** and toggle it on. Calls will ring your staff first — Maple only takes over if no one answers. **2. Turn off order taking:**  Go to **AI Agents → Orders** and **toggle off → Pickup Orders**, **Scheduled Orders**, and any **delivery** options.  This stops the agent from accepting new orders while still answering calls. **3. Update your welcome message:**  Go to **AI Agents → Message** and update the welcome message to something like: *"Thank you for calling \[Restaurant Name]! We're unable to take phone orders right now, but our team is here at the restaurant to help you. You can also order online at \[your website]. We'll be back to normal shortly!"* This keeps your customers informed and gives them an alternative while you sort things out — without having to turn everything off completely. All of these changes take effect immediately and can be reversed just as quickly.  Your dashboard is always there for you — nothing is permanent, and everything is adjustable. *** ### **Useful Links** * **Dashboard:** [app.maple.inc](https://app.maple.inc) * **Documentation:** [docs.maple.inc](https://docs.maple.inc) * **Email:** [hello@maple.inc](mailto:hello@maple.inc) * **Phone/Text:** +1 (929) 543-0229 # Complete your Onboarding Source: https://docs.maple.inc/onboarding Setting Up Your Maple Agent Complete your agent setup and get ready to go live. This guide walks you through the onboarding flow after your account and billing are set up. ## **Before You Begin** ### Make sure you have completed: * Created your Maple account * Entered your legal business name * Selected your plan and completed billing * Your restaurant's main phone number * A **second phone line** for handoff — this must be different from your main restaurant line. **Why do I need a second line?** When a customer needs to be transferred to a staff member, Maple calls your handoff number. If this is the same as your main line, Maple will pick up again instead of a human — creating a loop. A manager's cell or back-of-house line works perfectly. *** ### **Step 1 — Get started** After completing billing, you'll see a **Payment Successful** confirmation screen. Your merchant account is now ready. Get Started 3 Click **Setup Your First Location** to continue. *** ### **Step 2 — Set up your first location** You'll see a screen outlining what's needed to set up your location: Set Up Your First Location Set Up Your Location 2 Click **Get Started** to begin. *** ### **Step 3 — Look up your location** Maple will try to find your restaurant automatically to pre-fill your location details. Type your restaurant's name in the search bar. Select it and click **Confirm Location Details**. It will search for your restaurant online and pull the name, location, and hours of operation. Look Up Your Location If your location doesn't appear, click **Setup Location Manually** to enter your details by hand. *** ### **Step 4 — Create your Maple agent** You'll see a confirmation that your agent is ready to be created. Click **Get Started** to begin agent setup. Create Your First Maple Agent Get Started (create Your Maple Agent) *** ### **Step 5 — Assign a phone number to your agent** Maple will suggest an auto-assigned phone number for your agent. This is an internal number used for routing — your customers will never see it or dial it directly. Assign Phone Number Click **Assign Phone Number** to confirm. You can also click **Search For Other Numbers** if you'd prefer a different number or area code. *** ### **Step 6 — Set your welcome message** This is the first thing your customers hear when they call. Maple generates a default message based on your location name. Welcome Message You can customize this here, and anytime from your dashboard, to match your restaurant's tone. Keep it short, warm, and direct — up to 120 characters. Click **Continue** when ready. *** ### **Step 7 — Set up your handoff number** Handoff Number When Maple can't help a customer — or they ask to speak with someone — the call gets transferred to your handoff number. Enter a phone number that your staff can answer. This **must be different from your main restaurant line**. Handoff Number Set Up Click **Save & Continue**. If you'd like to skip this for now, click **Skip Handoff Number** — but we strongly recommend setting this up before going live. **Important:** Using the same number as your main line will cause an AI loop. The agent will pick up again instead of a staff member. *** ### **Step 8 — Continue with Call forwarding** Continue With Call Forwarding After setting this up, when customers call your existing restaurant number, calls are automatically forwarded to Maple. This will be the last step to get your agent live with Maple.  Select **Continue With Call Forwarding** to proceed with the recommended setup. Enable Call Forwarding Then **Skip Setup Verification** for now. Skip Set Up Verification *** ### **Step 9 — SMS setup *(optional)*** Maple can send SMS text messages to your customers — payment links, booking confirmations, online ordering links, and more. Skip SMS Choose: **No, Skip SMS Setup** — skip for now and set it up later from your dashboard. Then click **Complete Onboarding**. SMS setup requires business verification (A2P compliance). You can always come back to this later. *** ### **Step 10 — You're all set! 🎉** Exit Onboarding Click **Exit Onboarding** to go to your dashboard and continue setting up. *** ### **What to do next** Before going live, we recommend completing these steps in your dashboard: * **[Maple Dashboard Overview](/dashboard-overview)** — a complete walkthrough of your dashboard * **[Going Live](/going-live)** — test your agent and switch on call forwarding *** ### **Need Help?** * **Email:** [hello@maple.inc](mailto:hello@maple.inc) * **Live support hours:** Monday–Friday, 9 AM – 6 PM EST * **Dashboard:** [app.maple.inc](https://app.maple.inc) # Delivery Configuration Source: https://docs.maple.inc/orders/config/delivery Set up delivery zones, fees, and providers for your restaurant Maple supports delivery orders with flexible configuration for zones, fees, and driver management. You can use a third-party delivery service provider (DSP) network, your own fleet of drivers (BYOF), or a combination of both. ## Delivery modes Maple Fleet connects your restaurant to a network of delivery service providers (DSPs) including DoorDash Drive and Uber Direct. Maple handles courier assignment, tracking, and status updates automatically. **How it works:** * Customer places a delivery order through Maple * Maple requests a delivery quote from the DSP network * A courier is assigned and dispatched to your restaurant * The customer receives real-time status updates via SMS * Delivery fees and tips are handled through Maple **Best for:** Restaurants without their own delivery drivers, or as overflow capacity during peak times. Use your own delivery drivers. Maple handles order-taking and sends delivery details to your team. **How it works:** * Customer places a delivery order through Maple * The order is sent to your POS with delivery details * Your team manages driver assignment and dispatch * You define your own delivery zones and fees **Configuration options:** * Set a default delivery fee for all BYOF orders * Define delivery zones to control your coverage area * Optionally accept tips on delivery orders **Best for:** Restaurants with existing delivery staff who want to keep using their own drivers. Combine BYOF for nearby deliveries with the DSP network for longer-distance orders or overflow. **How it works:** * Define BYOF zones for areas your drivers cover * Orders outside your BYOF zones automatically route to the DSP network * Seamless fallback when your fleet is unavailable **Best for:** Restaurants that want to handle nearby deliveries in-house while expanding their delivery radius. ## Setting up delivery Navigate to the delivery settings in your Maple dashboard and select your delivery model (Maple Fleet or BYOF). Define the geographic areas where you offer delivery. You can create polygon zones (custom shapes) or circle zones (radius-based). Configure delivery fees, minimum order amounts, and estimated delivery times for each zone. Place a test delivery order to verify zone coverage, fee calculation, and order routing. ## Delivery zones Delivery zones define where your restaurant can deliver. Each zone has its own fee, minimum order amount, and estimated delivery time. ### Zone types | Zone Type | Description | Best for | | ----------- | ----------------------------------- | ---------------------------------------------- | | **Polygon** | Custom-drawn shape on a map | Precise coverage areas, city boundaries | | **Circle** | Radius-based zone around your store | Simple setups, even coverage in all directions | **Polygon zones** let you draw a freeform boundary on the map. Use these when your delivery area follows streets, highways, or other irregular boundaries. **Circle zones** define a radius (in miles) centered on your store's location. The system generates the boundary automatically — you only need to set the distance. Circle zones are useful when you want uniform coverage in all directions. Both zone types work the same way during ordering. When a customer provides a delivery address, Maple checks whether it falls inside the zone boundary. For circle zones, the boundary is an approximation of the radius you set. ### Zone settings For each delivery zone, configure: | Setting | Description | | ------------------ | ---------------------------------------------------------- | | **Delivery fee** | Flat fee charged to the customer for delivery | | **Minimum order** | Orders below this amount cannot be placed for delivery | | **Estimated time** | Estimated delivery time shown to customers during ordering | | **Zone priority** | When zones overlap, higher-priority zones take precedence | You can create multiple zones with different fees and minimums. For example, a lower fee for nearby areas and a higher fee for farther zones. ## Pickup instructions If you use the Maple Fleet (DSP) network, you can provide pickup instructions for drivers. These instructions tell the courier where and how to pick up the order at your restaurant. Navigate to your store's delivery settings and enter pickup instructions in the text area. Examples: * "Enter through the side door on Oak Street" * "Ask for the online order at the front counter" * "Ring the buzzer and say you're picking up a delivery order" ## Payment for delivery orders Delivery orders require card payment upfront. Cash and pay-in-store are not available for delivery orders. Payment for delivery orders is processed through your configured payment provider (Stripe, Gravity, or Shift4) before the order is sent to your POS. The delivery fee is added to the order total automatically based on the customer's delivery address and your zone configuration. **Toast pay-on-delivery requires cash enabled in StreamOrders.** If you accept pay-on-delivery (pay-in-store) orders routed to Toast through StreamOrders, you must enable **cash** as an accepted payment method for delivery in StreamOrders. Otherwise Toast rejects the order (`decision_failed` / "payment method declined") and it never reaches the kitchen. See [StreamOrders: accepted payment methods](https://help.streamorders.com/en/articles/13441016). ### Delivery fee billing How the delivery fee is settled depends on your payment processor: * **Stripe merchants:** Maple takes the delivery fee directly. * **Non-Stripe merchants:** The delivery fee is added as a line item on the order, so you collect it at checkout, and Maple then invoices it back. This is a net-zero passthrough — not an extra charge. ## Delivery order flow Customer calls or texts Maple and requests delivery. The AI collects their delivery address. Maple checks if the address falls within your delivery zones and calculates the delivery fee. The AI confirms the order, delivery fee, and estimated delivery time with the customer. Customer pays upfront via card. The delivery fee is included in the total. The order is submitted to your POS system for preparation. For Maple Fleet orders, a courier is assigned and dispatched automatically. For BYOF, your team handles dispatch. The customer receives SMS updates as the delivery progresses (driver assigned, picked up, on the way, delivered). ## Troubleshooting The customer's address may be outside your configured delivery zones. Check your zone boundaries in the dashboard and expand them if needed. The AI will inform the customer and offer pickup as an alternative. Verify the fee settings for each delivery zone. If zones overlap, the higher-priority zone's fee is used. Ensure your Maple Fleet setup is complete and that the delivery territory is configured for your area. During high-demand periods, courier availability may be limited. Contact Maple support if assignment is consistently failing. ## Early access Interested in Maple Fleet delivery? We're working with select partners. Email us to get started with Maple Fleet delivery ## Next Steps Set up payment processing Manage your menu Return to orders overview Launch your Maple AI # Menu Management Source: https://docs.maple.inc/orders/config/menu-management Manage your menu for order taking How to manage your menu depends on your integration type. ## POS-Integrated Merchants ### Automatic Sync * Changes made in POS * Reflects in Maple within 5 minutes * Real-time inventory * Price updates automatic ### What Syncs * All menu items * Modifiers and options * Categories * Availability/86'd items * Prices and taxes Make all menu changes in your POS system, not in Maple. ## Manual Setup Merchants ### Menu Builder * Add items manually * Set prices and descriptions * Create modifiers * Organize categories ### Managing Items * Quick edit mode * Bulk updates * Import/export CSV * Duplicate items ### Daily Management * Mark items unavailable * Update prices * Add specials * Remove sold-out items ## Best Practices * Clear item names * Detailed descriptions * Logical categorization * Regular updates * Accurate pricing ## Menu Optimization * Popular items first * Clear modifier options * Upsell suggestions * Seasonal highlights ## Next Steps * [Complete Setup](/orders/overview) * [Test Ordering](/quickstart) * [Monitor Analytics](/dashboard-overview#step-8--analytics) # Payment Methods Configuration Source: https://docs.maple.inc/orders/config/payment-methods Set up payment processing for orders Configure how customers pay for orders through Maple. Payment processing is set up during onboarding and can be adjusted from your dashboard. ## Payment flow When a customer places an order, Maple handles payment based on your configuration: 1. **Order totaled** — The AI confirms the order and calculates the total including tax, delivery fees, and tips 2. **Payment method selected** — The customer chooses to pay now (via link) or pay in store (if available) 3. **Payment processed** — For card payments, the customer receives a secure payment link via SMS 4. **Order submitted** — Once payment is confirmed, the order is sent to your POS ## Payment methods ### Pay by link The default payment method. After an order is placed, the customer receives an SMS with a secure payment link. The link opens a checkout page where they can pay with: * Credit or debit cards (Visa, Mastercard, Amex, Discover) * Apple Pay * Google Pay Payment links are sent immediately after the order is confirmed. If the customer doesn't pay, they receive automatic reminders at 5, 10, and 20 minutes. ### Pay in store Customers pay at the restaurant when they pick up their order. This option is only available for **pickup orders** — delivery orders always require upfront payment. Pay in store is not supported by all POS systems. The following POS integrations require payment before order submission and **do not support pay in store**: Square, Smile, SkyTab, and SpotOn. | Supports pay-in-store | Does not support pay-in-store | | ----------------------------------------------------------- | ----------------------------- | | Toast, Clover, NCR Aloha, NCR Voyix, Quantic, Tray, Chowbus | Square, SkyTab, Smile, SpotOn | ### Auto-convert to pay in store When enabled, if a customer has not paid via their payment link after all reminders are sent, the order is automatically converted to pay in store. This prevents orders from being lost due to unpaid payment links. **How it works:** 1. Customer places a pickup order and receives a payment link via SMS 2. Maple sends automatic payment reminders at **5 minutes**, **10 minutes**, and **20 minutes** if the link is unpaid 3. After all reminders are exhausted with no payment, the order converts to pay in store 4. The order is submitted to your POS as an unpaid pickup order 5. The merchant receives an SMS notification explaining that the order was switched to pay in store Auto-convert only applies to **pickup orders**. Delivery orders always require upfront card payment and are never auto-converted. This setting is configured per location in the Maple dashboard under your agent's phone channel settings. It requires that your POS supports pay-in-store orders and that pay in store is enabled as a payment method for pickup. ## Payment providers Maple uses a payment provider to process card payments. The provider is configured automatically based on your POS integration: | POS Integration | Payment Provider | | ---------------------------------------------------------- | ---------------- | | Smile | Gravity | | SkyTab | Shift4 | | SpotOn | CyberSource | | Toast, Square, Clover, NCR Aloha, NCR Voyix, Tray, Chowbus | Stripe | Payment processing is included with Maple — no separate merchant account is needed for Stripe-powered integrations. Smile, SkyTab, and SpotOn use their respective POS payment systems. ## Payment rules by order type | Order Type | Pay by link | Pay in store | Notes | | ------------ | ----------- | ----------------- | ----------------------------- | | **Delivery** | ✅ Required | ❌ | Card payment required upfront | | **Pickup** | ✅ | ✅ (POS-dependent) | Customer chooses at checkout | ## Configuration options * **Minimum order amounts** — set per delivery zone or order type * **Tip suggestions** — customize default tip percentages * **Service fees** — optional fee added to orders * **Tax calculation** — handled automatically based on location ## Tips Maple can suggest and collect tips during the ordering process: * Tip suggestions are presented to the customer * Tips are included in the payment link total * Tip amounts are reported in your dashboard and POS ## Refunds Refunds are processed through your payment provider: * Full or partial refunds available * Refund processing depends on your payment provider * Refund status is tracked in the Maple dashboard ## Security * PCI DSS Level 1 compliant * End-to-end encryption * Card tokenization (card numbers never stored) * Fraud prevention and monitoring Payment processing is included with your Maple plan — no separate merchant account needed for Stripe or Gravity. ## Testing payments In test mode, use standard test card numbers (e.g., `4242 4242 4242 4242` for Stripe). Create orders through the voice AI or dashboard and complete payment via the link. Confirm the paid order appears correctly in your POS system. Review payment settlements in your Maple dashboard. ## Next Steps Set up delivery zones and fees Manage your menu Return to orders overview Launch your Maple AI # Orders Module FAQ Source: https://docs.maple.inc/orders/faq Common questions about order taking features Common questions about the Orders Module and order taking functionality. ## General questions Toast, Square, Clover, SpotOn, Smile, SkyTab, NCR Aloha, NCR Voyix, Quantic, Tray, and Chowbus. Manual setup is available for unsupported systems. Yes for all integrations except Quantic. KYC typically takes 2-3 business days. With KYC: 2-3 business days. Without KYC (Quantic): same day. No, orders must be cancelled and re-placed for modifications. Yes. Maple supports delivery through the Maple Fleet (DSP) network and BYOF (Bring Your Own Fleet). You can configure delivery zones, fees, and minimum order amounts. See the [delivery configuration guide](/orders/config/delivery). ## Payment questions Credit/debit cards (Visa, Mastercard, Amex, Discover) via secure payment links. Pay-in-store is available for pickup orders on supported POS systems. If auto-convert is enabled and a customer doesn't pay their payment link after reminders, the order can be automatically switched to pay in store so it still reaches the kitchen. See [payment methods configuration](/orders/config/payment-methods) for details. Toast, Clover, NCR Aloha, NCR Voyix, Quantic, Tray, and Chowbus support pay-in-store for pickup orders. Square, SkyTab, Smile, and SpotOn require upfront card payment. Payment processing is included in your Maple plan. Tips can be suggested and collected as part of the payment link. Tip amounts are reported in your dashboard and POS. ## Menu questions POS-integrated merchants: update in your POS and changes sync automatically. Manual setup merchants: update in the Maple dashboard. Yes, mark items as 86'd in real-time from your POS or dashboard. Yes, all modifiers and options sync automatically from your POS. ## Delivery questions Yes, through the Maple Fleet delivery network (powered by First Delivery). You can also use your own drivers (BYOF). Configure delivery zones in your store's delivery settings. You can use circle zones (radius-based) or polygon zones (custom boundaries). See the [delivery configuration guide](/orders/config/delivery). No. Delivery orders always require upfront card payment regardless of POS system. ## Next Steps * [View setup guide](/orders/overview) * [Choose POS integration](/orders/pos/overview) * [Contact support](mailto:hello@maple.inc) # Orders Module Overview Source: https://docs.maple.inc/orders/overview Enable automated order-taking via phone and SMS with POS integration The Orders Module transforms your Maple voice assistant into a full order-taking system that integrates directly with your POS. Take orders 24/7 via phone and SMS, with automatic menu syncing and payment processing. The Orders Module is an add-on to Maple Voice Core. Ensure Maple Voice Core is configured before setting up orders. ## Key features ### Order taking * **Voice orders**: Natural conversation order-taking over the phone * **SMS orders**: Text-based ordering for customer convenience * **Menu intelligence**: Understands modifications, substitutions, and special requests * **Upselling**: Intelligently suggests add-ons and promotions * **Order confirmation**: Repeats order back for accuracy ### POS integration * **Direct sync**: Orders appear instantly in your POS * **Menu updates**: Automatic sync when you update your POS menu * **Inventory aware**: Knows what's available and what's 86'd * **Multi-location**: Support for multiple restaurant locations ### Payment processing * **Pay by phone**: Secure card processing during the call * **Pay via link**: Customer receives a payment link via SMS * **Pay in store**: Option for pickup orders (supported POS systems only) * **Tips & fees**: Automatic calculation and processing ### Delivery * **Maple Fleet**: Third-party delivery network powered by First Delivery * **BYOF**: Bring your own fleet — use your own delivery drivers * **Delivery zones**: Define delivery areas with circle or polygon zones * **Zone-based fees**: Set fees and minimums per delivery zone ## Supported POS systems Full integration with KYC Full integration with KYC Full integration with KYC Full integration with KYC Full integration with KYC Full integration with KYC Full integration with KYC Full integration with KYC Full integration (no KYC) Full integration with KYC Full integration with KYC No POS integration, KYC required KYC (Know Your Customer) verification is required for all POS integrations except Quantic. This process typically takes 2-3 business days. ## Setup process The setup process varies based on your POS system: ### With POS integration Ensure Maple Voice Core is configured Submit business verification (except Quantic) Authenticate and sync your POS system Set up payment methods and rules Place test orders to verify flow ### Without POS integration (Manual) Ensure Maple Voice Core is configured Submit business verification Manually create menu in Maple dashboard Set up payment processing Verify order flow and notifications ## Menu management ### POS-integrated merchants * Menu syncs automatically from your POS * Updates reflect within minutes * Manage all changes in your POS system * 86'd items update in real-time ### Manual setup merchants * Build and manage menu in Maple dashboard * Update items, prices, and availability * Set modifiers and options * Configure special requests handling ## Payment configuration ### Payment methods * **Credit/debit cards**: All major cards accepted * **Pay in store**: For pickup orders on supported POS systems * **Digital wallets**: Apple Pay, Google Pay (via payment links) ### Pay-in-store support Not all POS systems support pay-in-store (unpaid) orders. Here's the breakdown: | POS System | Pay-in-store supported? | | ---------- | ----------------------- | | Toast | ✅ Yes | | Clover | ✅ Yes | | NCR Aloha | ✅ Yes | | NCR Voyix | ✅ Yes | | Quantic | ✅ Yes | | Tray | ✅ Yes | | Chowbus | ✅ Yes | | Square | ❌ No | | SkyTab | ❌ No | | Smile | ❌ No | | SpotOn | ❌ No | ### Payment rules | Order Type | Payment Options | | ------------ | -------------------------------------------- | | **Delivery** | Always require upfront card payment | | **Pickup** | Pay now or pay in store (if POS supports it) | ## Order flow Initiates order via phone or SMS Captures items, modifications, and details Repeats order and provides total Handles payment per your configuration Order appears in POS/kitchen system Gives customer order number and estimated time ## Delivery configuration If you offer delivery: * Set delivery zones (circle or polygon) and fees * Configure minimum order amounts per zone * Set estimated delivery times * Use Maple Fleet (DSP) or your own drivers (BYOF) [Learn more about delivery configuration →](/orders/config/delivery) ## Analytics & reporting Track your order performance: * **Order volume**: Daily, weekly, monthly trends * **Average order value**: Track ticket sizes * **Popular items**: Best-selling menu items * **Order timing**: Peak hours and patterns * **Payment methods**: Customer preferences * **Conversion rate**: Calls that result in orders ## Prerequisites Before setting up the Orders Module: * ✅ Maple Voice Core fully configured * ✅ Business information complete * ✅ POS system access (if integrating) * ✅ Bank account for payments * ✅ KYC documentation ready (if required) ## Next Steps Ensure you're ready to start Select your POS system Set up payment processing Common questions answered ## Need help? * **POS-specific guides**: [Troubleshooting by POS](/troubleshooting/pos-specific) * **Order issues**: [Orders troubleshooting](/troubleshooting/orders) # Chowbus Source: https://docs.maple.inc/orders/pos/chowbus Connect Maple to your Chowbus POS system for automatic order processing Connect Maple directly to your Chowbus POS system for seamless order processing. Orders taken via phone or SMS appear instantly in your Chowbus system. Chowbus integration requires KYC verification, which typically takes 2-3 business days. ## Prerequisites Before starting, ensure you have: * ✅ Admin access to Chowbus * ✅ Maple Voice Core configured * ✅ Business documentation for KYC * ✅ Bank account information * ✅ Chowbus API credentials ## Setup Process Submit business verification documents to enable payment processing. Provide your Chowbus API credentials to connect your account. Select which locations to enable for Maple ordering. Your Chowbus menu syncs automatically. Verify that items, modifiers, categories, and prices imported correctly. Place test orders to verify the full order flow. ## KYC Requirements Submit the following documents: * Business registration (LLC, Corp, etc.) * EIN or Tax ID letter * Owner's government-issued ID * Bank statement or voided check KYC processing takes 2-3 business days. Start this immediately to avoid delays. ## Connecting Chowbus Chowbus uses credential-based authentication: 1. Go to **Orders Module** → **POS Integration** 2. Select **Chowbus** from the available options 3. Enter your Chowbus API credentials 4. Maple validates the connection and imports your menu Contact your Chowbus representative if you need help locating your API credentials. ## Menu Synchronization Your Chowbus menu syncs automatically to Maple: * ✅ All menu items and prices * ✅ Categories and organization * ✅ Modifier groups and modifiers * ✅ Item availability updates * ✅ Multi-language menu item names (translations) Menu changes should be made in Chowbus. Changes sync to Maple automatically. ## Payment Processing Chowbus supports the following payment options: * Credit/debit card processing * Pay-in-store for pickup orders ### Payment Rules | Order Type | Payment Options | | ------------ | ----------------------- | | **Pickup** | Pay now or pay in store | | **Delivery** | Card required upfront | ## Order Management Maple orders appear in Chowbus as: * Source: "Maple - Phone" or "Maple - SMS" * Standard Chowbus order format * Full reporting integration ### Order Flow 1. Customer places order via Maple (phone or SMS) 2. Maple validates the order against your Chowbus menu 3. Order is submitted to Chowbus with line items and modifiers 4. Kitchen receives the order through your normal Chowbus workflow ## Multi-Language Support Chowbus menus often include translations for menu items. Maple uses the English item names for voice ordering and maps them to the correct Chowbus menu items, including items with Chinese, Korean, or other language names. ## Troubleshooting * Verify items are active in Chowbus - Check that categories are published - Wait 5-10 minutes for sync to complete * Contact support if issues persist * Confirm the integration is active - Check that Chowbus is online and credentials are valid - Verify location settings - Review error logs in the dashboard * Verify your API credentials are correct - Check that credentials haven't expired - Contact your Chowbus representative for new credentials if needed * Cancellation depends on the order status in Chowbus - Orders already in preparation may not be cancellable - Check the Maple dashboard for cancellation error details ## Support * **Chowbus Support**: Contact your Chowbus representative * **Maple Support**: Text +1 929 543 0229 ## Next Steps Set up payment processing Set up delivery zones and fees # Clover Source: https://docs.maple.inc/orders/pos/clover Connect Maple to your Clover POS system Connect Maple directly to Clover for automatic order processing. Clover integration requires KYC verification (2-3 business days). ## Prerequisites * Clover merchant account * API access enabled * Maple Voice Core configured * KYC documents ready ## Setup Process Submit verification documents Generate in Clover dashboard Enter merchant ID and token Verify order flow ## Clover-Specific Features * Menu synchronization * Real-time inventory * Employee management * Tax configuration * Tip suggestions ## Configuration Options * Order types (pickup/delivery) * Prep time settings * Payment methods * Receipt preferences ## Troubleshooting * Verify API permissions * Check merchant ID * Confirm menu published * Test in sandbox first ## Next Steps * [Configure Payments](/orders/config/payment-methods) * [Menu Management](/orders/config/menu-management) * [Launch Checklist](/quickstart) # FoodTec Source: https://docs.maple.inc/orders/pos/foodtec Connect Maple to FoodTec for menu sync and order injection Connect Maple to FoodTec for automatic menu synchronization and AI-powered order injection. ## Prerequisites FoodTec provides three separate `user:password` credential pairs for each location: * Menu export API * Order validation API * Order acceptance API You will also need the location's FoodTec base URL, including its port when applicable. Maple requires an HTTPS URL. ## Setup 1. Select **FoodTec** in the POS picker. 2. Enter the base URL and the three API credential pairs. 3. Optionally set the menu order type and order source. The defaults are `Pickup` and `Third Party`. 4. Maple verifies the credentials and configured order type, then activates the integration. Activation starts a menu synchronization automatically. ## Menu synchronization Maple imports FoodTec categories, item sizes, prices, and selectable ingredients. Each `(category, item, size)` variant becomes a Maple menu item. FoodTec items marked unavailable are shown as out of stock in Maple. Specials, coupons, qualifiers, halves, and conditional modifier dependencies are not synchronized. Menu and stock changes should be managed in FoodTec. You can trigger a manual menu resync from the Maple dashboard. ## Orders Before an order is accepted, Maple sends it to FoodTec for validation. FoodTec supplies the authoritative subtotal, tax, fees, total, and repriced items; Maple submits those validated totals, fees, and items with the acceptance request, adding the tip to the submitted total. Pickup and delivery orders, customer details, notes, tips, scheduled times, and selected ingredients are supported. Customer phones are sent to FoodTec as `AAA-XXX-NNNN`; non-NANP numbers are rejected before validation. Merchant-owned delivery orders are submitted to FoodTec as `Delivery`, but the pre-payment validation prices them as pickup, so FoodTec's own delivery charge is not collected from the customer. Maple Fleet delivery orders are submitted to FoodTec as pickup. ## Cancellation FoodTec cancellation uses its void endpoint. FoodTec identifies a void request by Maple's original external reference. Maple retains and passes that reference to FoodTec when cancelling an order; the FoodTec ticket number is retained in the submission metadata for support use. ## Troubleshooting * Verify that all three credential pairs use the `user:password` format. * Verify that the base URL is HTTPS and includes the correct store port. * Confirm that the configured order type is enabled for the FoodTec location. * If menu items are missing, check their FoodTec availability and size-price rows. # Genius Source: https://docs.maple.inc/orders/pos/genius Connect Maple to your Genius (Heartland Restaurant) POS system **Coming soon.** The Genius integration is in final certification and not yet generally available. Contact your Maple representative to join the waitlist. Connect Maple to Genius (Heartland Restaurant) for AI-powered ordering with automatic menu sync and direct order injection. ## Prerequisites Before starting, ensure you have: * ✅ Your location's Genius API key (from the Heartland Restaurant portal). This is the only key you enter — the partner authentication key is configured once by Maple and applies to every location. * ✅ Maple Voice Core configured * ✅ Location configuration ## Setup process Provide the Genius API key for this restaurant in the Maple dashboard. Maple verifies it live against your Genius location. Select the Genius house account that should record Maple-paid orders on the check, or leave checks unpaid for staff to settle at the register. If your Genius location has a service charge configured, pick the one that should record the delivery fee on orders your own drivers deliver — or choose not to record it. This step is skipped when your location has no service charge to select. Your menu imports automatically from Genius. Verify items, sizes, modifiers, and prices, then go live. ## Features * Automatic menu synchronization, including 86'd / out-of-stock items and ingredients * Full modifier support, including per-item modifier configurations, size pricing, and context options (Extra / Light / On Side) * Tax and totals calculated by Genius — what the guest pays always matches the Genius check * Real-time updates: menu publishes and stock changes push from Genius to Maple instantly * Orders appear directly on your Genius POS and KDS ## Payment processing Maple can collect payment before the order is sent to Genius, recording it against the house account you selected during setup, or send the order unpaid for staff to settle in store. * Pay-in-store is supported — the check arrives open on the POS * Tips collected by Maple ride on the order to Genius * On orders your own drivers deliver, the driver tip rides on the check and the delivery fee is recorded as the service charge you selected during setup ## Menu synchronization Your Genius menu syncs automatically: * ✅ All menus (groups), categories (sections), items, and sizes with per-size pricing * ✅ Modifiers with per-item defaults, exclusions, and included-quantity rules * ✅ Context options (Extra / Light / On Side) with their pricing * ✅ 86'd (out-of-stock) items and ingredients Menu changes should be made in Genius. Publishing a menu or changing stock pushes to Maple automatically, and you can trigger a manual sync from the Maple dashboard. ## Troubleshooting * Verify the items and their sections are marked available online in Genius - Trigger a manual menu sync from the Maple dashboard - Contact support if issues persist * Confirm the Genius location is online - Verify the location API key is still valid - Contact support with the order number ## Support * **Heartland Support**: Contact your Heartland representative * **Maple Support**: Text +1 929 543 0229 ## Next Steps Set up delivery zones and fees Launch your Maple AI # Manual Setup (No POS) Source: https://docs.maple.inc/orders/pos/manual-setup Configure order taking without POS integration Set up order taking without a POS system or for unsupported systems. Manual setup requires KYC verification and manual menu entry. ## When to Use Manual Setup * No POS system * Unsupported POS * Testing Maple before POS integration * Simple menu operations ## Setup Process Submit business verification Enter items, prices, modifiers Set up payment processing Verify order notifications ## Menu Builder ### Adding Items * Item name and description * Price and tax settings * Categories and organization * Modifiers and options ### Managing Availability * Mark items as unavailable * Set temporary 86'd items * Schedule seasonal items * Update prices instantly ## Order Notifications Orders sent via: * Email notifications * SMS alerts * Dashboard display * Printer integration (optional) Manual entry of orders into your system may be required. ## Need Your POS Integrated? If your POS isn't currently supported, let us know. We prioritize integrations based on merchant demand. Email us with your POS system details and we'll explore adding it to our roadmap ## Next Steps * [Build Your Menu](/orders/config/menu-management) * [Configure Payments](/orders/config/payment-methods) * [Go Live](/going-live) # NCR Aloha Source: https://docs.maple.inc/orders/pos/ncr-aloha Connect Maple to your NCR Aloha Cloud POS system Connect Maple directly to your NCR Aloha Cloud POS for automatic order processing. NCR Aloha Cloud integration requires KYC verification, which typically takes 2-3 business days. ## Prerequisites Before starting, ensure you have: * ✅ Admin access to NCR Aloha Cloud * ✅ Maple Voice Core configured * ✅ Business documentation for KYC * ✅ Bank account information * ✅ NCR Aloha Cloud API credentials ## Setup Process Submit business verification documents Authorize Maple to access your Aloha Cloud system Select which sites/locations to enable Import and verify menu configuration Place test orders to verify setup ## KYC Requirements Required documents: * Business registration (LLC, Corp, etc.) * EIN or Tax ID letter * Owner's government-issued ID * Bank statement or voided check KYC processing takes 2-3 business days. Start this immediately to avoid delays. ## Configuration ### Site Setup * Single or multi-site configuration * Per-location settings * Revenue center mapping * Kitchen routing rules ### Menu Synchronization Automatic sync includes: * All menu items and pricing * Modifiers and combos * Categories and subcategories * Item availability status ## Order Processing ### Order Flow 1. Customer calls or texts order 2. Maple processes and validates 3. Order sent to NCR Aloha Cloud 4. Appears on kitchen display 5. Standard Aloha workflow ### Order Details Orders appear with: * Source identification * Customer information * Special instructions * Payment status ## Advanced Features ### Multi-Revenue Centers * Configure per revenue center * Different menus per center * Routing based on order type ### Reporting Integration * Orders included in all reports * Source tracking for analytics * Performance metrics available ## Troubleshooting Common issues: * **Menu sync delays**: Wait 10 minutes, check Aloha settings * **Order routing**: Verify site configuration * **Payment issues**: Check processor settings ## Support * **NCR Support**: Contact your NCR representative * **Maple Support**: Text +1 929 543 0229 * **Documentation**: Check dashboard for guides ## Next Steps * [Configure Payment Methods](/orders/config/payment-methods) * [Test Your Integration](/quickstart) # NCR Voyix Source: https://docs.maple.inc/orders/pos/ncr-voyix Connect Maple to your NCR Aloha Essentials POS system Connect Maple directly to your NCR Aloha Essentials POS for streamlined order processing. NCR Aloha Essentials integration requires KYC verification, which typically takes 2-3 business days. ## Prerequisites Before starting, ensure you have: * ✅ Admin access to NCR Aloha Essentials * ✅ Maple Voice Core configured * ✅ Business documentation for KYC * ✅ Bank account information * ✅ Aloha Essentials site ID ## Setup Process Submit business verification documents Generate and provide API credentials Link your Aloha Essentials account Import menu and verify setup Validate integration with test orders ## KYC Requirements Submit the following documents: * Business registration documents * EIN or Tax ID letter * Owner's government-issued ID * Bank account verification ## Key Differences from Aloha Cloud ### Simplified Setup * Streamlined configuration process * Essential features focused * Faster deployment timeline * Single-location optimized ### Menu Management * Direct menu import * Basic modifier support * Simple category structure * Manual 86'd item management ## Configuration Options ### Basic Settings * Store hours * Prep times * Payment methods * Order types (pickup/delivery) ### Menu Import What syncs from Aloha Essentials: * Menu items and prices * Basic modifiers * Categories * Combo meals Complex modifier groups may require manual configuration in Maple. ## Order Processing ### How Orders Appear * Identified as external orders * Customer name and phone * Items with modifications * Special instructions field ### Payment Handling * Credit card processing * Cash on pickup option * Gift card support (if enabled) * House accounts (if configured) ## Common Setup Issues * Verify items are active in Aloha - Check category assignments - Review import logs * Confirm API credentials - Check network connectivity - Verify site ID correct * Update prices in Aloha - Re-sync menu in Maple - Check for active promotions ## Best Practices Keep your menu simple and well-organized for best voice ordering experience. Test ordering flow weekly to catch any sync issues early. ## Support Resources * **NCR Support**: Your NCR representative * **Maple Support**: Text +1 929 543 0229 * **Quick Help**: Check dashboard FAQ ## Next Steps * [Payment Configuration](/orders/config/payment-methods) * [Test Your Setup](/quickstart) # POS Integration Overview Source: https://docs.maple.inc/orders/pos/overview Select the right integration path for your restaurant Select your current POS system below to see setup requirements and timeline. If you don't have a POS or yours isn't listed, choose Manual Setup. ## Supported POS systems Toast POS Square POS Clover POS Full integration with OAuth and KYC Smile POS SkyTab POS NCR Aloha POS NCR Voyix POS Quantic POS Full integration with KYC Full integration with KYC ## No POS or unsupported system **KYC required**: Yes | **Setup time**: 2-3 days | **Menu sync**: Manual entry | **Best for**: Restaurants without POS or with unsupported systems ## What is KYC? KYC (Know Your Customer) is a verification process required for payment processing. It involves: * Business registration verification * Owner identity verification * Bank account verification * Tax ID confirmation Quantic merchants skip KYC because payment processing is handled through Quantic's existing merchant accounts. ## Integration benefits ### Why choose POS integration? Changes made to your menu in your POS system are reflected in Maple automatically, eliminating the need for manual updates. Price changes sync automatically, and new items appear without delay, ensuring your menu is always up to date. Real-time inventory integration ensures that 86'd items are updated automatically, inventory levels remain accurate, seasonal items are managed properly, and modifier availability is always tracked. Orders are sent directly to the kitchen without manual entry. This reduces errors and speeds up order processing. ### When manual setup makes sense Manual setup works well for phone-order-only operations, simple menus, low order volume, or restaurants planning to add a POS system later. Manual setup is also a fit if you use a legacy POS system, a custom solution, are waiting for a future integration, or want to test Maple before fully integrating. ## Authentication methods POS integrations use one of two authentication methods: | Method | POS Systems | How it works | | --------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | **OAuth** | Toast, Square, Clover, SpotOn | You're redirected to the POS login page to authorize Maple. Tokens are managed automatically. | | **Credentials** | SkyTab, Smile, Quantic, NCR Aloha, NCR Voyix, Tray, Chowbus | You enter API credentials or account details in the Maple dashboard. | ## Pay-in-store support Not all POS systems support accepting unpaid (pay-in-store) orders: | Supports pay-in-store | Does not support pay-in-store | | ----------------------------------------------------------- | ----------------------------- | | Toast, Clover, NCR Aloha, NCR Voyix, Quantic, Tray, Chowbus | Square, SkyTab, Smile, SpotOn | Delivery orders always require upfront payment regardless of POS system. ## Timeline breakdown ### Day 1: Start setup * Submit KYC documents (if required) * Connect POS credentials * Initial configuration ### Day 2-3: Verification * KYC processing * POS connection testing * Menu sync verification ### Day 3-4: Go live * Test orders * Staff training * Launch to customers Quantic merchants can typically go live the same day since KYC is not required. ## Next Steps Select your POS above Start manual configuration Review requirements first Discuss options with our team ## Frequently asked questions Yes, you can migrate between POS systems or from manual to integrated at any time. We support multi-location setups with different POS systems. Contact support for configuration. No, Maple integrates with your existing configuration without requiring changes. Yes, we provide a sandbox environment for testing before going live. # Qu Source: https://docs.maple.inc/orders/pos/qu Connect Maple to your Qu POS system **Coming soon.** The Qu integration is in final certification and not yet generally available. Contact your Maple representative to join the waitlist. Connect Maple to Qu for AI-powered ordering with automatic menu sync and direct order injection. ## Prerequisites Before starting, ensure you have: * ✅ Your Qu store ID (provided by Qu) * ✅ Maple Voice Core configured * ✅ Location configuration ## Setup process Provide the numeric Qu store ID for this restaurant in the Maple dashboard. Select the Qu order channel Maple orders should flow through (typically "Web"). Select the Qu order type for Maple orders (typically "Take Out" or "Web Orders"). Your menu imports automatically from Qu. Verify items, modifiers, and prices, then go live. ## Features * Automatic menu synchronization (hourly), including 86'd / out-of-stock items * Full modifier support, including nested modifier groups and portions * Tax and totals calculated by Qu — what the guest pays always matches the Qu check * Orders appear directly on your Qu POS and KDS ## Payment processing Maple collects payment before the order is sent to Qu. The payment is recorded on the Qu check so your reports stay accurate. * Payment links are supported for pickup orders * Pay-in-store is **not** supported for Qu — Qu requires the check to be fully paid when Maple places it ## Menu synchronization Your Qu menu syncs automatically: * ✅ All menu items and prices (including portion pricing) * ✅ Modifiers, nested modifier groups, and included-quantity rules * ✅ Categories * ✅ 86'd (out-of-stock) items Menu changes should be made in Qu. Changes sync to Maple within the hour, or trigger a manual sync from the Maple dashboard. ## Troubleshooting * Verify items are active on the selected Qu order channel and order type - Trigger a manual menu sync from the Maple dashboard - Contact support if issues persist * Confirm the Qu store is online - Verify the order channel and order type selected during setup are enabled in Qu * Contact support with the order number ## Support * **Qu Support**: Contact your Qu representative * **Maple Support**: Text +1 929 543 0229 ## Next Steps Set up delivery zones and fees Launch your Maple AI # Quantic Source: https://docs.maple.inc/orders/pos/quantic Connect Maple to your Quantic POS system Connect Maple to Quantic for order management with same-day setup. Quantic integrations do **not** require KYC — setup is same-day. ## Why no KYC? Quantic handles payment processing through existing merchant accounts, eliminating separate KYC requirements. This means you can go live the same day you connect. ## Prerequisites Before starting, ensure you have: * ✅ Quantic account ID * ✅ API credentials * ✅ Maple Voice Core configured * ✅ Location configuration ## Setup process Provide your Quantic account details in the Maple dashboard. Map your Maple stores to the corresponding Quantic locations. Your menu imports automatically from Quantic. Verify items, modifiers, and prices. Start taking orders immediately — no KYC wait time. ## Features * Multi-location support * Automatic menu synchronization * Pay-in-store supported for pickup orders * Centralized reporting * Bulk menu management ## Payment processing Quantic handles payment collection through its own payment links. Maple does not generate a separate payment link for this integration. * Pay-in-store is supported for pickup orders * Delivery orders require upfront payment ## Menu synchronization Your Quantic menu syncs automatically: * ✅ All menu items and prices * ✅ Modifiers and options * ✅ Categories * ✅ Item availability Menu changes should be made in Quantic. Changes sync to Maple automatically. ## Troubleshooting * Verify items are active in Quantic - Check API credentials - Wait a few minutes for sync to complete - Contact support if issues persist * Verify account ID and location IDs - Ensure locations are active in Quantic - Check that each Maple store is mapped to the correct location ## Support * **Quantic Support**: Contact your Quantic representative * **Maple Support**: Text +1 929 543 0229 ## Next Steps Set up delivery zones and fees Launch your Maple AI # SkyTab by Shift4 Source: https://docs.maple.inc/orders/pos/skytab Connect Maple to your SkyTab POS system # SkyTab by Shift4 Integration Connect Maple directly to your SkyTab by Shift4 POS for seamless order processing. SkyTab integration requires KYC verification, which typically takes 2-3 business days. ## Prerequisites Before starting, ensure you have: * ✅ Admin access to SkyTab * ✅ Voice Core configured * ✅ Business documentation for KYC * ✅ Bank account information * ✅ SkyTab merchant ID ## Setup Process Submit business verification documents Authorize Maple to access your SkyTab system Select which locations to enable Verify menu imported correctly Place test orders to verify setup ## KYC Requirements Same as other integrated POS systems: * Business registration documents * EIN or Tax ID letter * Owner's government-issued ID * Bank statement or voided check KYC processing takes 2-3 business days. Start this immediately to avoid delays. ## Configuration ### SkyTab Integration Features * Real-time menu synchronization * Automatic price updates * Modifier and option support * 86'd item management * Multi-location support ### Payment Processing SkyTab by Shift4 includes integrated payment processing: * Credit/debit card support * Gift card integration * Loyalty program compatibility * Contactless payment options ## Menu Synchronization Your SkyTab menu automatically syncs to Maple: * All menu items and prices * Modifiers and variations * Categories and sections * Real-time availability updates * Special pricing and promotions Menu changes must be made in SkyTab. Changes sync to Maple within 5 minutes. ## Order Management Maple orders appear in SkyTab as: * Source: "Maple - Phone" or "Maple - SMS" * Standard SkyTab orders * Full reporting integration * Kitchen display compatible ### Order Flow 1. Customer places order via Maple 2. Order appears in SkyTab immediately 3. Kitchen receives via display/printer 4. Standard SkyTab workflow applies ## Multi-Location Support For restaurants with multiple locations: * Configure each location separately * Different menus per location * Location-specific pricing * Centralized reporting available ## Troubleshooting * Verify items are active in SkyTab - Check visibility settings - Wait 5-10 minutes for initial sync - Contact support if issues persist * Confirm integration is active - Check SkyTab is online - Verify location settings - Review error logs in dashboard * Verify Shift4 payment settings - Check processor status - Review decline reasons - Confirm customer card details ## Advanced Features ### Shift4 Payments Integration * Seamless payment processing * Lower transaction fees * Integrated reporting * PCI compliance handled ### Loyalty & Marketing * Customer data capture * Loyalty point accumulation * Marketing campaign integration * Customer analytics ## Support For SkyTab-specific issues: * **SkyTab Support**: 1-877-851-0128 * **Shift4 Support Portal**: support.shift4.com * **Maple Support**: Text +1 929 543 0229 ## Next Steps * [Configure Payment Methods](/orders/config/payment-methods) * [Test Your Integration](/quickstart) * [Review Menu Optimization](/best-practices/menu-optimization) # Smile Source: https://docs.maple.inc/orders/pos/smile Connect Maple to your Smile POS system Connect Maple directly to your Smile POS system for seamless order processing. Smile integration requires KYC verification, which typically takes 2-3 business days. ## Prerequisites Before starting, ensure you have: * ✅ Admin access to Smile * ✅ Maple Voice Core configured * ✅ Business documentation for KYC * ✅ Bank account information ## Setup Process Submit business verification documents Smile uses Gravity as its payment processor. During onboarding, Maple connects your Smile account to Gravity for payment processing. This step must be completed before orders can be submitted to Smile. Authorize Maple to access your Smile system Select which locations to enable Verify menu imported correctly Place test orders to verify setup ## KYC Requirements Same as other integrated POS systems: * Business registration documents * EIN or Tax ID letter * Owner's government-issued ID * Bank statement or voided check ## Payment Processing Smile requires all orders to be paid before they are submitted to the POS. Pay-in-store is not supported with Smile. Smile uses **Gravity** as its payment provider. When a customer places an order: 1. Customer receives a payment link via SMS 2. Customer pays through the Gravity-powered checkout page 3. Once payment is confirmed, the order is submitted to Smile 4. The order appears in your Smile POS with payment already applied If Gravity onboarding is not complete, orders cannot be submitted to Smile. Ensure the onboarding process has fully completed before going live. ## Menu Synchronization Your Smile menu syncs to Maple via webhooks: * All menu items and prices * Modifiers and options * Categories and organization * Real-time availability updates Menu sync is webhook-based, so updates from Smile may take a few moments to appear in Maple. If your menu doesn't appear after setup, wait a few minutes for the webhook to process. ## Order Management Maple orders appear in Smile as: * Source: "Maple - Phone" or "Maple - SMS" * Standard Smile orders * Full reporting integration ## Troubleshooting Verify that Gravity onboarding is complete. Smile requires payment via Gravity before order submission. Check the Maple dashboard for any onboarding errors. Menu sync uses webhooks and may take a few minutes. If the menu still doesn't appear after 10 minutes, contact Maple support to trigger a manual sync. Ensure Gravity onboarding is fully complete. If the customer sees an error on the payment page, the Gravity connection may need to be re-established. ## Support For Smile-specific issues, contact your Smile representative. For Maple integration support, text +1 929 543 0229. ## Next Steps * [Configure Payment Methods](/orders/config/payment-methods) * [Test Your Integration](/quickstart) # SpotOn Source: https://docs.maple.inc/orders/pos/spoton Connect Maple to your SpotOn POS system for automatic order processing Connect Maple directly to your SpotOn POS system for seamless order processing. Orders taken via phone or SMS appear instantly in your SpotOn system. SpotOn integration requires KYC verification, which typically takes 2-3 business days. ## Prerequisites Before starting, ensure you have: * ✅ Admin access to SpotOn * ✅ Maple Voice Core configured * ✅ Business documentation for KYC * ✅ Bank account information ## Setup Process Submit business verification documents to enable payment processing. Authorize Maple to access your SpotOn system through OAuth. You'll be redirected to SpotOn to approve the connection. Choose which SpotOn locations to enable for Maple ordering. Your SpotOn menu syncs automatically. Verify that items, modifiers, and prices imported correctly. Place test orders to verify the full order flow from call to kitchen. ## KYC Requirements Submit the following documents: * Business registration (LLC, Corp, etc.) * EIN or Tax ID letter * Owner's government-issued ID * Bank statement or voided check KYC processing takes 2-3 business days. Start this immediately to avoid delays. ## Connecting SpotOn SpotOn uses OAuth for authorization: 1. Go to **Orders Module** → **POS Integration** 2. Select **SpotOn** from the available options 3. Click **Connect SpotOn Account** 4. You'll be redirected to SpotOn's login page 5. Enter your SpotOn credentials and approve Maple's access 6. You'll be redirected back to the Maple dashboard You need SpotOn admin permissions to authorize the integration. Contact your SpotOn administrator if you don't have access. ## Menu Synchronization Your SpotOn menu syncs automatically to Maple: * ✅ All menu items and prices * ✅ Modifiers and option groups * ✅ Categories and organization * ✅ Item availability updates * ✅ Price changes Menu changes should be made in SpotOn. Changes sync to Maple automatically. ## Payment Processing SpotOn integration uses CyberSource for payment processing: * Credit/debit card support * Secure tokenized transactions * PCI-compliant processing Pay-in-store is not available for SpotOn orders. All orders require upfront card payment. ### Payment Rules | Order Type | Payment Options | | ------------ | --------------------- | | **Pickup** | Card required upfront | | **Delivery** | Card required upfront | ## Order Management Maple orders appear in SpotOn as: * Source: "Maple - Phone" or "Maple - SMS" * Standard SpotOn order format * Full reporting integration * Kitchen display compatible ### Order Flow 1. Customer places order via Maple (phone or SMS) 2. Order appears in SpotOn immediately 3. Kitchen receives the order via display or printer 4. Standard SpotOn workflow applies ## Multi-Location Support For restaurants with multiple locations: * Configure each location separately * Different menus per location * Location-specific pricing * Centralized reporting available ## Troubleshooting * Verify items are active in SpotOn - Check visibility settings - Wait 5-10 minutes for sync to complete - Contact support if issues persist * Confirm the integration is active in the Maple dashboard - Check that SpotOn is online - Verify the correct location is selected - Review error logs in the dashboard * Verify payment settings are configured correctly - Check processor status - Review decline reasons in the dashboard - Confirm customer card details are valid * Re-authorize the SpotOn connection from the dashboard - Go to **Orders Module** → **POS Integration** → **Reconnect** ## Support * **SpotOn Support**: Contact your SpotOn representative * **Maple Support**: Text +1 929 543 0229 ## Next Steps Set up payment processing Set up delivery zones and fees # Square Source: https://docs.maple.inc/orders/pos/square Connect Maple to your Square POS system Connect Maple directly to Square for seamless order processing. Square integration requires KYC verification (2-3 business days). ## Prerequisites * Square account with admin access * Square for Restaurants (recommended) * Maple Voice Core configured * KYC documents ready ## Setup Process Submit verification documents OAuth authorization Payment and order options Place test orders ## Square-Specific Features * Real-time menu sync * Modifier support * Inventory tracking * Customer profiles * Loyalty integration ## Payment Configuration * Card processing via Square * Square gift cards * Digital wallets * Cash on pickup ## Best Practices * Keep Square app updated * Use Square categories * Enable auto-gratuity * Test thoroughly ## Next Steps * [Configure Payments](/orders/config/payment-methods) * [Set Up Delivery](/orders/config/delivery) * [Go Live](/quickstart) # Toast Source: https://docs.maple.inc/orders/pos/toast Connect Maple to your Toast POS system for automatic order processing Connect Maple to your Toast POS system for seamless order processing. Orders taken via phone or SMS appear instantly in your Toast system. Toast integration requires KYC verification, which typically takes 2-3 business days. ## Prerequisites Before starting, ensure you have: * ✅ Admin access to Toast * ✅ Maple Voice Core configured * ✅ Business documentation for KYC * ✅ Bank account information * ✅ Toast location ID(s) ## Setup Process Submit business verification documents Authorize Maple to access your Toast system Choose which locations to enable Set up payment methods and rules Place test orders to verify setup ## Step 1: KYC Verification ### Required Documents * Business registration (LLC, Corp, etc.) * EIN or Tax ID letter * Owner's government-issued ID * Bank statement or voided check * Business address verification KYC processing takes 2-3 business days. Start this immediately to avoid delays. ### Submit Documents 1. Navigate to **Orders Module** → **Setup** 2. Click **Start KYC Verification** 3. Upload required documents 4. Complete owner information 5. Submit for review ## Step 2: Connect Toast Account Once KYC is approved: 1. Go to **Orders Module** → **POS Integration** 2. Select **Toast** from the options 3. Click **Connect Toast Account** 4. You'll be redirected to Toast login 5. Enter your Toast credentials 6. Approve Maple's access request 7. Return to Maple dashboard You need Toast admin permissions to authorize the integration. Contact your Toast administrator if you don't have access. ## Step 3: Configure Locations ### Single Location 1. Your location will auto-populate 2. Verify the information is correct 3. Enable order processing 4. Set default prep times ### Multiple Locations 1. All locations will be listed 2. Toggle each location on/off 3. Configure settings per location: * Prep times * Payment methods * Delivery zones (if applicable) * Operating hours ## Step 4: Menu Sync Your Toast menu will automatically sync to Maple: ### What Syncs Automatically * ✅ All menu items and prices * ✅ Modifiers and options * ✅ Categories and organization * ✅ 86'd items (real-time) * ✅ Price changes * ✅ Availability schedules * ✅ Menu hours * Hidden Toast items are not synced ### Sync Timing * Initial sync: 5-10 minutes * Updates: Within 5 minutes * 86'd items: Real-time Menu changes must be made in Toast. Changes sync to Maple automatically. ## Step 5: Payment Configuration ### Payment Methods Configure which payment types to accept: * **Credit/Debit cards**: Toast Hosted Checkout * **Pay in store**: Pickup only, if enabled * **Gift cards**: Not supported * **House accounts**: Not supported ### Payment Rules Set when customers pay: | Order Type | Payment Options | | ------------ | ----------------------- | | **Delivery** | Always pay upfront | | **Pickup** | Pay now or pay in store | | **Curbside** | Pay now or pay in store | | **Dine-in** | Not applicable | **Pay-on-delivery requires cash enabled in StreamOrders.** For pay-on-delivery (pay-in-store) orders routed to Toast through StreamOrders, you must enable **cash** as an accepted payment method for delivery in StreamOrders. Otherwise Toast rejects the order (`decision_failed` / "payment method declined") and it never reaches the kitchen. See [StreamOrders: accepted payment methods](https://help.streamorders.com/en/articles/13441016). ## Step 6: Order Flow Settings ### Prep Times Set realistic prep times by order type: * Pickup orders: Default 15-20 minutes * Delivery orders: Default 30-45 minutes * Large orders: Automatic adjustment ### Order Confirmation Configure confirmation settings: * Enable order readback * Set confirmation method (number or email) * Configure receipt delivery ### Special Requests Define how to handle: * Allergy notifications * Special preparations * Custom modifications * Notes to kitchen ## Step 7: Testing Before going live, test thoroughly: ### Test Checklist 1. **Place Test Order** * Call your Maple number * Order a few items with modifications * Verify order appears in Toast 2. **Check Order Details** * Correct items and quantities * Modifications captured * Pricing accurate * Payment processed correctly 3. **Test Edge Cases** * 86'd items handled properly * Large orders * Special requests * Different payment methods Use Toast's training mode for testing without affecting real inventory or reports. ## Going Live ### Launch Checklist * ✅ Staff trained on new orders appearing * ✅ Kitchen knows about Maple orders * ✅ Phone number updated on website/Google * ✅ Test orders successful * ✅ Payment processing verified ### Soft Launch Strategy 1. Start with limited hours 2. Monitor first few orders closely 3. Gather staff feedback 4. Adjust settings as needed 5. Expand to full hours ## Managing Orders ### In Toast POS Maple orders appear as: * Source: "Maple - Phone" or "Maple - SMS" * Standard Toast orders * All normal Toast features available * Reports include Maple orders ### Disconnecting Toast * Remove Maple in Toast Partner Connect * Toast sends a partner removal webhook * Maple deactivates the Toast integration automatically ### In Maple Dashboard View and manage: * Call recordings and transcripts * Order history * Failed order reasons * Customer information * Performance metrics ## Common Issues & Solutions * Check items are active in Toast - Verify menu visibility settings - Wait 5 minutes for sync - Contact support if persists * Verify integration is active - Check Toast is online - Confirm location is selected - Review error logs in dashboard * Verify payment settings - Check processor connection - Review decline reasons - Confirm customer card details * Update prices in Toast - Wait for sync (5 minutes) - Check for active promotions - Verify price levels ## Advanced Features ### Revenue Centers * Not used * Orders are placed through the configured takeout or delivery dining option ### Loyalty * Not supported * Saved cards are not supported ### Catering Orders For large/advance orders: * Extended prep times * Deposit requirements * Special instructions * Scheduled ordering ## Best Practices **Menu Optimization**: Keep menu item names clear and pronunciation-friendly for voice ordering. **Modifier Management**: Limit modifiers to essential options to reduce complexity. **Regular Testing**: Make monthly test orders to ensure everything works smoothly. ## Support Resources * **Toast Support**: For POS-specific issues * **Maple Support**: [hello@maple.inc](mailto:hello@maple.inc) * **Integration Status**: Check dashboard for real-time status * **Documentation**: [Toast API Docs](https://doc.toasttab.com) ## Next Steps Set up payment processing Configure delivery zones Manage your menu Launch to customers # Tray Source: https://docs.maple.inc/orders/pos/tray Connect Maple to your Tray POS system for automatic order processing Connect Maple directly to your Tray POS system for seamless order processing. Orders taken via phone or SMS appear instantly in your Tray system. Tray integration requires KYC verification, which typically takes 2-3 business days. ## Prerequisites Before starting, ensure you have: * ✅ Admin access to Tray * ✅ Maple Voice Core configured * ✅ Business documentation for KYC * ✅ Bank account information * ✅ Tray API credentials ## Setup Process Submit business verification documents to enable payment processing. Provide your Tray API credentials to connect your account. Select which locations to enable for Maple ordering. Your Tray menu syncs automatically. Verify that items, modifiers, and prices imported correctly. Place test orders to verify the full order flow. ## KYC Requirements Submit the following documents: * Business registration (LLC, Corp, etc.) * EIN or Tax ID letter * Owner's government-issued ID * Bank statement or voided check KYC processing takes 2-3 business days. Start this immediately to avoid delays. ## Connecting Tray Tray uses credential-based authentication: 1. Go to **Orders Module** → **POS Integration** 2. Select **Tray** from the available options 3. Enter your Tray API credentials 4. Maple validates the connection and imports your menu Contact your Tray representative if you need help locating your API credentials. ## Menu Synchronization Your Tray menu syncs automatically to Maple: * ✅ All menu items and prices * ✅ Sections and subsections * ✅ Option groups and modifiers * ✅ Item availability updates * ✅ Price changes Menu changes should be made in Tray. Changes sync to Maple automatically. ## Payment Processing Tray supports the following payment options: * Credit/debit card processing * Pay-in-store for pickup orders ### Payment Rules | Order Type | Payment Options | | ------------ | ----------------------- | | **Pickup** | Pay now or pay in store | | **Delivery** | Card required upfront | ## Order Management Maple orders appear in Tray as: * Source: "Maple - Phone" or "Maple - SMS" * Standard Tray order format * Full reporting integration ### Order Flow 1. Customer places order via Maple (phone or SMS) 2. Maple validates the order against your Tray menu 3. Order is submitted to Tray 4. Kitchen receives the order through your normal Tray workflow ## Troubleshooting * Verify items are active in Tray - Check that sections are published - Wait 5-10 minutes for sync to complete - Contact support if issues persist * Confirm the integration is active - Check that Tray is online and credentials are valid - Verify location settings * Review error logs in the dashboard * Verify your API credentials are correct - Check that credentials haven't expired - Contact your Tray representative for new credentials if needed ## Support * **Tray Support**: Contact your Tray representative * **Maple Support**: Text +1 929 543 0229 ## Next Steps Set up payment processing Set up delivery zones and fees # Orders Module Prerequisites Source: https://docs.maple.inc/orders/prerequisites Requirements before enabling order taking Ensure you meet these requirements before setting up the Orders Module. ## Required setup Before starting: * ✅ Maple Voice Core fully configured * ✅ FAQs configured * ✅ Phone number active * ✅ Business information verified * ✅ Bank account ready (for payments) ## Business requirements ### Documentation needed * Business registration (LLC, Corp, etc.) * EIN or Tax ID * Bank account details * Owner identification ### For POS integration * Admin access to POS system * Location IDs * API credentials (varies by POS) * Menu already in POS ### For manual setup * Complete menu with prices * Modifier options * Availability schedule * Category organization ## KYC requirements Required for: Toast, Square, Clover, SpotOn, Smile, SkyTab, NCR Aloha, NCR Voyix, Tray, Chowbus, Manual Not required for: Quantic ### KYC documents * Government-issued ID * Business license * Bank statement * Proof of address KYC verification takes 2-3 business days. Start early. ## Technical requirements * Stable internet connection * Modern web browser * Smartphone for testing * Access to email ## Team preparation * Identify who will manage orders * Train staff on new order flow * Prepare for test period * Plan launch communication ## Next Steps Select your system Begin verification # Quickstart Source: https://docs.maple.inc/quickstart Get your Maple voice AI up and running in 15 minutes ## Before You Begin You'll need: * Your restaurant's basic information (name, address, hours) * A valid credit card for billing * About 10 minutes Use your restaurant's main email address for easier team management later. 1. Visit [**app.maple.inc**](https://app.maple.inc) and sign in or create your account 2. You'll land on the **Welcome to Maple** screen 3. Click **Get Started** to begin setting up your merchant account You'll be asked how you'd like to complete onboarding: * **Complete On My Own** — you'll fill in all the details yourself * **Invite A Team Member** — send the onboarding to a manager to complete on your behalf Select your preferred option and click **Continue**. **Tip:** If you're the owner or manager setting things up directly, select "Complete On My Own" to get through this fastest. Enter the **legal name of your business entity** — for example, *Maple's Burgers LLC*. This is used for your merchant account and billing records. It will **not** be visible to your customers. Once you see the green checkmark confirming the name is valid, click **Save & Continue**.\ \ Choose the option that best describes your business: Currently, we support the following store types: Restaurant and Salon. Select **Restaurant / Cafe** and click **Continue as Restaurant**. Enter how many locations you operate under this business entity. Use the **–** and **+** buttons to adjust. Click **Continue** when done. You can always add more locations later from your dashboard. Select the plan that fits your needs. Maple Voice is required and included in all plans. Add Orders or Bookings if needed. Click **Continue** when ready. You can change your plan at any time from your dashboard. \ Review your subscription summary. Click **Open Secure Checkout Link** to proceed to payment. On the checkout page: 1. Enter your **card number, expiration date, and CVC** 2. Enter your **cardholder's name** 3. Select your **country** and enter your **ZIP code** 4. Optionally add a **promotion code** if you have one 5. Click **Subscribe** to complete your purchase All payments are processed securely through **Stripe**. Your card will be billed monthly.  A **Processing Your Payment** screen will appear — wait for it to complete before proceeding. Enter your restaurant's **main phone number**. This will be visible to your customers and can be changed later.  Click **Save & Continue**. This is your existing restaurant line — the one customers already call. You'll set up call forwarding at the end of onboarding. Enter your restaurant's website URL if you have one. Maple uses this to learn more about your business and tailor the AI to your needs. If you don't have a website, click **Skip Adding A Website**. Otherwise, enter your URL and click **Save & Continue**. You're all set with the basics! Here's what to do next: * **Complete your Onboarding** * **Maple Dashboard Overview** * **Need Help?** ## What's Next? Adjust voice settings and personality Add more FAQs and train your AI Start taking orders automatically Enable text messaging capabilities Set detailed hours and holidays Monitor performance and insights ## Need Help? * **Common Issues**: Check our [Maple Voice Core Troubleshooting](/troubleshooting/voice-core) * **Live Support**: Available Monday-Friday, 9 AM - 6 PM EST # Maple Voice Core FAQ Source: https://docs.maple.inc/voice-core/faq Common questions about Maple Voice Core features Common questions and answers about Maple Voice Core functionality. ## General Questions Maple Voice Core is the base module included with all Maple accounts. It handles incoming calls, answers FAQs, and provides restaurant information 24/7. Yes, Maple Voice Core is required as the foundation for all other modules including Orders. Yes, you can port your existing number to Maple. The process takes 5-7 business days. Maple supports English (always on), Spanish, and Mandarin Chinese. Cantonese is in beta with limited access. French is available in beta by request. Additional languages are added regularly — contact Maple support for the latest availability. See [voice configuration](/voice-core/voice-configuration) for setup details. ## Setup Questions Basic Maple Voice Core setup takes about 15-30 minutes. You can start receiving calls immediately. Yes, you can change voice settings, personality, and language options at any time. No, the setup is designed for non-technical users with step-by-step guidance. ## Feature Questions Yes, Maple can handle unlimited simultaneous calls without busy signals. Yes, Maple works 24/7 and can provide different responses during closed hours. Yes, calls can be transferred to staff based on your configured rules. ## Next Steps * [View all features](/voice-core/overview) * [Start setup](/quickstart) * [Contact support](mailto:hello@maple.inc) # FAQ Setup Source: https://docs.maple.inc/voice-core/faqs Configure FAQs to train your voice AI Your FAQs function as the knowledge base for your Maple voice AI. Think of it as training a new employee—the more information you provide, the better your AI performs. The AI uses your FAQs as reference material to answer customer questions naturally in conversation.