# 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**
**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:
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.
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.
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.
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.
***
### **Step 4 — Bookings *(if enabled)***
Click **Bookings** to manage phone reservations.
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.
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
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.
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.
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**
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:
* **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.
**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:
* **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:
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**
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.
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.
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:
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.
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.
***
### **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.
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.
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**
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**.
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**
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.
Then **Skip Setup Verification** for now.
***
### **Step 9 — SMS setup *(optional)***
Maple can send SMS text messages to your customers — payment links, booking confirmations, online ordering links, and more.
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! 🎉**
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
Full integration with OAuth and KYC
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.
## Adding FAQs
To edit your FAQs, go to [Edit FAQ](https://app.maple.inc/edit_faq) in the portal and click **+ Add to FAQ**. Enter your question and provide a comprehensive answer with all relevant details.
The AI doesn't look for exact question matches. It uses your FAQs as reference material to answer naturally in
conversation. You don't need question variations or multiple translations—just write clear, complete answers in
English. The AI automatically handles variations and translates to other languages during customer calls.
You can only add and delete FAQs—there's no edit function yet. To update an FAQ, delete the old one and add a new one
with your changes.
## Getting Started with Sample Templates
To help you get started quickly, use our pre-built FAQ templates based on real Maple customers:
**Note:** This FAQ is provided as an example template. Please feel free to edit, add, or remove questions and answers to fit your store's specific services, policies, and customer needs.
1. **What is your address?**\
A: \[Insert full street address, city, state, ZIP].
2. **Do you offer delivery?**\
A: Yes, we deliver within \[xx] miles. You can order online, or I can transfer you to our store representative now.
3. **Is there a delivery fee or order minimum?**\
A: Yes, there is a delivery fee of \[amount] with an order minimum of \[amount] before tax and tip.
4. **How long do orders take?**\
A: Pickup orders are typically ready in \[15–25 minutes]. Delivery usually takes \[35–55 minutes], depending on volume and distance.
5. **Can I schedule an order for later?**\
A: Yes— I can transfer you to our store representative for scheduling the order.
6. **How can I check the status of my order?**\
A: Use the confirmation link, or I can transfer you to our store representative.
7. **Can I modify my order after placing it?**\
A: I can transfer you to our store representative for that —we'll do our best to accommodate changes.
8. **Can I cancel my order?**\
A: If preparation hasn't started, we may be able to cancel. Call the store at \[handoff number]; refunds depend on order status.
9. **Do you accept online payments?**\
A: Yes—major credit/debit cards and digital wallets (e.g., Apple Pay, Google Pay) are accepted online, you can pay it via the text link.
10. **Do you accept credit cards in-store?**\
A: Yes—we accept cash and all major credit/debit cards. \[Note AmEx policy if applicable.]
11. **Do you accept American Express?**\
A: \[Yes/No]. We also accept \[Visa/Mastercard/Discover].
12. **Is gratuity automatically added?**\
A: A \[xx%] service charge may apply to parties of \[x]+ or catered events.
13. **Do you offer gift cards?**\
A: Yes—both e-gift and physical gift cards are available. Purchase in-store or online.
14. **Do you have a loyalty or rewards program?**\
A: \[Yes/No]. If yes, customers can sign up at checkout or ask our staff.
15. **Do you take reservations?**\
A: \[Yes/No]. For large parties (\[x]+), please call ahead to check availability.
16. **Do you host private events or catering?**\
A: Yes—please call \[phone] or email \[events/catering email]. Allow at least days' notice for large orders.
17. **Is outdoor seating available?**\
A: \[Yes/No]. Patio seating is \[first-come or by reservation], weather permitting.
18. **Where can I park?**\
A: Parking is \[lot/street/validated]. Spaces are first-come, first-served.
19. **Is the restaurant accessible?**\
A: Yes—entrance, restrooms, and main dining area are wheelchair accessible. Call us on arrival for assistance if needed.
20. **Are pets allowed?**\
A: Service animals are welcome. Pets are \[allowed/not allowed] on the patio per local regulations.
21. **Is there a dress code?**\
A: Casual and family-friendly.
22. **Do you have TVs/Wi-Fi?**\
A: \[TVs for major games/Wi-Fi available]. Ask staff for the network and password.
23. **What languages do you support?**\
A: We primarily speak English. If you need another language, I can transfer you to someone who may be able to assist further. Let us know and we'll do our best to assist.
24. **What is your policy on outside food and drink?**\
A: Outside beverages are not permitted. Exceptions may apply for celebration cakes—please call ahead.
25. **Do you partner with third-party delivery apps?**\
A: \[Yes/No]. Ordering directly is recommended for best pricing and service.
26. **How do I apply for a job?**\
A: Check openings at \[careers page] or drop off a résumé in person.
27. **Do you offer franchises or partnerships?**\
A: Please email \[business@…] with your inquiry.
28. **What's your holiday schedule?**\
A: Holiday hours will be posted on our website and social channels. You can also call to confirm.
29. **How do you announce weather-related closures or delays?**\
A: We update our website banner, social media, and notify customers with active orders.
30. **Do you provide receipts or invoices for business expenses?**\
A: Yes—ask at checkout or reply to your order confirmation email to request a PDF copy.
31. **Do you handle tax-exempt purchases?**\
A: Yes—please provide your tax-exempt certificate before payment.
32. **What are your health & safety practices?**\
A: We follow local health guidelines, sanitize high-touch areas regularly, and offer contactless options upon request.
33. **Lost and found—who do I contact?**\
A: Call \[phone] or email \[email] with a description of the item and your visit details.
34. **Can I take photos or film inside?**\
A: Casual photos are welcome. For professional shoots, please request permission at \[email].
**Note:** This FAQ is provided as an example template. Please feel free to edit, add, or remove questions and answers to fit your store's specific services, policies, and customer needs.
1. **What is the business address?**\
A: \[Insert business address]
2. **Do you accept walk-ins or appointments only?**\
A: We offer both walk-ins and online appointments. If you'd like to book now, we can send you the booking link.
3. **Can I walk in without an appointment?**\
A: Availability and wait times vary. We recommend checking our online booking for the most up-to-date availability.
4. **How long will I wait for walk-in service?**\
A: Let me transfer your call to the store manager, who can provide details.
5. **Do you have any openings today?**\
A: You can check our online booking for real-time availability.
6. **Can I book an appointment for today?**\
A: Yes, we'll send you the booking link.
7. **Can I book an appointment within 30 minutes?**\
A: Let me transfer your call to the store manager for assistance.
8. **What services do you offer?**\
A: \[Insert service categories]
9. **What are the service prices?**\
A: \[Insert service menu with price and duration]. If the menu has many items, list FAQs per category.
10. **Do you have package deals or membership discounts?**\
A: Yes, if packages or memberships are listed in the booking system. A: No, if not available.
11. **Can I request a specific technician or specialist?**\
A: Yes, you can select your preferred staff member in the booking system. If that option isn't available, add their name in the booking notes or speak to the store manager for assistance.
12. **Do you offer services for kids?**\
A: Yes, if kid services are listed in the booking system. A: No, if not available.
13. **Do you offer group or party appointments?**\
A: Yes, if group booking is supported. A: No, if not available.
14. **Do you provide a private room?**\
A: Your privacy is important to us. Let me transfer your call to the store manager.
15. **Do you offer senior or member discounts?**\
A: Let me transfer your call to the store manager for details.
16. **Do you have parking spaces?**\
A: Let me transfer your call to the store manager for details.
17. **Do you have accessible paths or parking?**\
A: Let me transfer your call to the store manager for details.
18. **Do you accept credit cards?**\
A: Yes, we accept both cash and major credit cards.
19. **Do you accept American Express?**\
A: Let me transfer your call to the store manager for details.
20. **Do you charge extra for credit card payments?**\
A: Let me transfer your call to the store manager for details.
21. **What is your late or cancellation policy?**\
A: Please see our website for details. I can also connect you with the store manager now.
22. **Can you provide your cancellation, store, and refund policies?**\
A: Let me transfer your call to the store manager for details.
23. **Do you sell gift certificates?**\
A: Yes, we offer gift cards. \[more details needed] or Let me transfer your call to the store manager for purchase.
24. **Are technicians licensed and insured?**\
A: Yes, all staff are fully trained and licensed.
25. **Is gratuity included?**\
A: Tax and tip are not included in the service price. Tips are always appreciated, and cash tips are preferred.
26. **Should I mention medical conditions before service?**\
A: Yes, please inform us of any conditions beforehand. This helps our technicians adjust techniques appropriately.
27. **What is your holiday schedule?**\
A: We are open on holidays.
28. **Can I speak to the store manager or owner to file a complaint?**\
A: Yes, let me transfer your call to the store manager.
29. **Can I get a refund if I was double-charged or overcharged?**\
A: Let me transfer your call to the store manager for assistance.
30. **Can I use a Groupon voucher?**\
A: Let me transfer your call to the store manager for assistance.
31. **Can I cancel my appointment?**\
A: Let me transfer your call to the store manager for assistance.
32. **Can I reschedule my appointment?**\
A: Let me transfer your call to the store manager for assistance.
33. **Do you speak Chinese, Spanish, or Vietnamese?**\
A: I speak English only, but I can connect you to an operator who may be able to assist.
Copy the relevant template and customize it for your business. You can start with 10-15 FAQs and add more based on
actual customer calls.
## What to Include
Cover the basics: hours, location, delivery/pickup policies, payment methods, dietary accommodations, reservations, and any special policies (dress code, pets, events). Add time-sensitive updates like holiday hours or construction notices, and set expiration dates for temporary information.
## Generate FAQs with AI
Click **Generate With AI** to automatically create FAQs from your website. Enter 1-3 website URLs (one per line) containing information you want to turn into FAQs, then click **Generate FAQs**.
The AI will scan your site for business hours, location, menu highlights, services, and contact information. AI-generated FAQs will be marked as "Automatic" in your FAQ list, while manually added FAQs are marked as "Manual."
Always review AI-generated FAQs for accuracy before going live.
## Testing & Maintenance
Test your FAQs by calling your AI and asking questions like "What are your hours?" or "Do you deliver?" to verify responses. The AI handles misspellings and variations automatically.
Review call transcripts weekly to identify gaps, add new FAQs for unanswered questions, and update information when things change. The more you refine your FAQs, the better your AI performs.
## Next Steps
Set operating hours
Customize voice settings
Make test calls
Monitor performance
# Maple Voice Core Overview
Source: https://docs.maple.inc/voice-core/overview
Understand the foundation of your Maple voice AI system
Maple Voice Core is the foundation of Maple—included with every account. It's a 24/7 AI phone answering system that handles incoming calls, answers customer questions using your custom FAQ knowledge base, and provides essential information about your business.
Maple Voice Core is included with all Maple accounts—no additional modules required.
Think of it as training a knowledgeable employee who never takes a break. Your AI uses the FAQs you provide to answer questions naturally, handle information requests, and route calls to staff when needed.
## What you can do with Voice Core
* Answer common questions about hours, location, menu, and services
* Handle calls 24/7, including after-hours inquiries
* Customize the AI's voice and personality to match your brand
* Transfer calls to staff when needed
* Support multiple languages automatically
* Track call analytics to understand customer needs
## Foundation for other modules
Maple Voice Core serves as the base for additional capabilities:
Add order-taking capabilities with POS integration, payment processing, and delivery.
Handle table reservations through natural conversation via OpenTable.
## Need help?
* **Setup guide**: [Quickstart](/quickstart)
* **Troubleshooting**: [Voice Core issues](/troubleshooting/voice-core)
* **Best practices**: [Voice scripts](/best-practices/voice-scripts)
# Getting a Phone Number
Source: https://docs.maple.inc/voice-core/phone/getting-number
Acquire a new phone number for your Maple voice AI
Get a new local or toll-free number for your Maple voice AI in minutes.
## Number Options
### Local Numbers
* Choose your area code
* Select from available numbers
* Instant activation
* Local presence advantage
### Toll-Free Numbers
* 1-800, 1-888, 1-877, etc.
* National reach
* Professional appearance
* Higher monthly cost
## Selection Process
Select local or toll-free
Enter desired area code or toll-free prefix
View available numbers matching criteria
Reserve and activate your number
## Number Features
* Voice and SMS capable
* Caller ID configuration
* Call forwarding options
* Multiple numbers per account
Numbers are activated immediately upon selection.
## Best Practices
* Choose easy-to-remember numbers
* Match existing area code if replacing
* Consider vanity numbers for marketing
* Reserve backup numbers
## Next Steps
* [Configure SMS](/voice-core/sms-a2p)
* [Set Up Voice Mail](/voice-core/voice-configuration)
# Porting Your Phone Number
Source: https://docs.maple.inc/voice-core/phone/porting
Transfer your existing phone number to Maple
**Porting is strongly discouraged.** The recommended setup is to use a new Maple-provided number and forward your
existing business line to it — this is faster, lower-risk, and keeps your original number with your current carrier.
Please contact Maple support before considering a port.
Keep your existing business number when switching to Maple. Porting ensures continuity for your customers while transitioning to AI call handling.
## When to Use Porting
Use this process when you want to move your phone number(s) from your current carrier to Maple so you can manage calls directly in your merchant account. This maintains your existing number that customers already know.
Prefer a faster option? You can [get a new Maple phone number](/voice-core/phone/getting-number) and update your
Google Business Profile immediately, rather than waiting for the port to complete.
## Before You Begin
You must be a fully onboarded merchant to port numbers
Ensure you have:
* [ ] A recent utility bill listing all numbers you want to port
* [ ] Your account number with your current carrier
* [ ] Account holder name and billing address (must match carrier records exactly)
* [ ] PIN or password (if required by your current carrier)
* [ ] Authority to make changes to the phone number account
Your numbers must be active and in service to be eligible for porting.
## Step-by-Step Process
### 1. Open the Port In Tab
1. Log into your [Maple merchant dashboard](https://app.maple.inc)
2. Navigate to **Merchant Settings** → **Port In**
3. Active port requests will be listed here with their status
### 2. Start a New Port Request
1. Click **Start Porting Request**
2. Upload your utility bill (must cover all numbers you want to port)
3. Enter the phone number(s) you want to port
* You can enter multiple numbers separated by commas or spaces
4. Click **Check Portability** to confirm eligibility
If your carrier requires a PIN and you don't know it, contact them to reset it before proceeding.
### 3. Complete the Losing Carrier Form
Provide the following information (must match your current carrier's records):
1. Select your customer type:
* Individual
* Business
2. Enter your account details:
* Account number with current carrier
* Account holder name
* Billing address
* PIN for each phone number (if required)
3. Review the phone numbers (carried over from previous step - cannot be changed here)
### 4. Schedule the Port Date
The earliest available port date is 7 days from today
Choose your preferred port date from the available options.
### 5. Add Notification Details
Enter email address(es) to receive status updates throughout the porting process. You can add multiple emails if needed.
### 6. Submit Your Request
1. Review all information for accuracy
2. Click **Submit Request**
3. Your request will appear in the Port In tab with:
* Current status
* Scheduled port date
* Any required actions
Monitor this page for updates until the port is complete.
## Timeline
The porting process typically takes **7-10 business days** from submission:
* **Day 1**: Submit request and upload documentation
* **Days 1-3**: Verification with your current carrier
* **Days 3-7**: Processing and coordination
* **Day 7-10**: Port completion
Your existing service will continue to work normally during the entire porting process.
## During the Port
* Your current number keeps working until the port completes
* You can use a temporary Maple number for testing in the meantime
* There may be a brief window (usually minutes) where calls don't connect during cutover
* You'll receive email notifications at each stage of the process
## Common Issues to Avoid
Avoid these common mistakes that cause port delays or failures:
* ❌ **Don't cancel your existing service** before the port is complete - this may cause you to lose your number
* ❌ **Mismatched information** - utility bill or account details that don't match your carrier's records
* ❌ **Incorrect or missing PIN** when required by your carrier
* ❌ **Port date earlier than 7 days** - minimum timeline cannot be shortened
* ❌ **Incomplete documentation** - ensure utility bill shows all numbers you want to port
## Frequently Asked Questions
Absolutely. If your number is eligible (most are), you can bring it over to Maple and keep your digits intact.
No. Once your number is ported to Maple, it leaves your old provider's system. If you want a new number from them,
you'll have to request it separately.
No worries—porting your number only moves the phone service. Your internet stays put. Just make sure to check with
your provider about any changes to your billing or bundle discounts.
Yes. Porting your phone number doesn't affect your internet service. You'll still be able to use your internet as
usual.
Once your number is ported, calls to that number will go to Maple. If you want to keep a phone line with your previous
provider, you'll need to request a new number from them.
Definitely. After your number is ported to Maple, just contact your old provider and ask for a new number. They'll set
you up with a fresh one.
Don't do it! Wait until your number is fully ported to Maple before making any changes or cancellations with your old
provider. Canceling too soon could mean losing your number.
There might be a brief window where calls don't connect, but typically, downtime is minimal. We'll keep you posted every step of the way.
## Next Steps
After your port is complete:
* [Configure Voice Settings](/voice-core/voice-configuration)
* [Set Up SMS](/voice-core/sms-a2p)
* [Test Your Setup](/quickstart)
# SMS A2P Registration
Source: https://docs.maple.inc/voice-core/sms-a2p
Enable SMS messaging for your Maple number
Register for Application-to-Person (A2P) messaging to enable SMS capabilities for customer communication.
## What is A2P?
A2P registration is required by carriers to:
* Prevent spam
* Ensure compliance
* Improve delivery rates
* Protect consumers
## Registration Process
Verify your business identity
Describe messaging purposes
Register message templates
Typically 2-3 business days
## Use Cases
Approved messaging types:
* Order confirmations
* Appointment reminders
* Customer service
* Marketing (with opt-in)
## Requirements
* EIN/Tax ID
* Business address
* Website
* Sample messages
* Privacy policy
Registration is required for SMS but not voice calls.
## Next Steps
* [Complete Setup](/quickstart)
* [Test SMS Features](/voice-core/overview)
* [Configure Auto-Responses](/voice-core/voice-configuration)
# Store Hours Configuration
Source: https://docs.maple.inc/voice-core/store-hours
Set your operating hours and special schedules
Configure your store's operating hours so your voice AI knows when you're open and can provide accurate information to customers.
Store hours control your AI's behavior and available capabilities. When the store is closed, certain features like
call passthrough are automatically disabled.
## How Store Hours Work
Store hours determine what your AI can do and which tools it has access to. The AI's capabilities change based on:
* Whether the store is currently open or closed
* Whether you have menus configured
* Whether menus are currently active (within menu hours)
* Whether ordering is enabled (pickup\_order or phone\_order)
You no longer need to include regular store hours in your FAQs—the AI uses the configured store hours automatically.
However, **keep holiday hours in your FAQs** as they require special handling.
## AI Behavior Based on Store Status
When **pickup\_order** or **phone\_order** is enabled, your AI's capabilities vary based on store and menu status:
### Store Open with Active Menus
* **Scenario**: Store has menus, is open, and menus are active
* **Capabilities**: Can answer detailed menu questions, take orders, provide FAQ information, share links, and transfer calls
### Store Open with Inactive Menus
* **Scenario**: Store has menus, is open, but menu hours have ended (menu hours end earlier than store hours)
* **Capabilities**: Can provide general menu recommendations, answer FAQ questions, share links, and transfer calls
### Store Closed with Active Menus
* **Scenario**: Store has menus, is closed, but menus are still active (unrealistic configuration where menu hours extend beyond store hours)
* **Capabilities**: Can provide general menu recommendations, answer FAQ questions, and share links
* **Note**: Call passthrough is disabled when store is closed
### Store Closed with Inactive Menus
* **Scenario**: Store has menus, is closed, and menus are inactive
* **Capabilities**: Can provide general menu recommendations, answer FAQ questions, and share links
### Store Open, No Menus
* **Scenario**: Store has no menus configured, is open
* **Capabilities**: Can answer FAQ questions, share links, and transfer calls (FAQ-only mode)
### Store Closed, No Menus
* **Scenario**: Store has no menus configured, is closed
* **Capabilities**: Can answer FAQ questions and share links (FAQ-only mode)
## Setting Up Store Hours
### Navigate to Store Hours
1. Click **Locations** in the sidebar
2. Select your store location
3. Click the **Store Hours** tab
You'll see a table showing each day of the week. Days with warning icons (⚠️) indicate the store is closed on those days.
Click **Add Store Hours** on the right side of any day to configure that day's schedule.
In the configuration popup, set when your store opens and closes for the day (your actual operating hours, not when you stop taking orders). Toggle **Open For Business** off for days you're closed.
**Hour Gaps** are for split shifts or breaks during the day (e.g., closing between lunch and dinner service). Click **+ Add Hour Gap** to add a break period with start and end times.
Once you've configured the day, click **Save Store Hours**. You'll see the day update with a checkmark (✓) and the times displayed.
Note the red door update when the location is marked as closed.
## Best Practices
**Store Hours vs Menu Hours**
* Set your actual closing time in store hours
* Use menu availability times to indicate last call for orders
* The AI's capabilities automatically adjust based on these settings
**Split Shifts**
* Use hour gaps for lunch/dinner restaurants
* Example: Open 11 AM - 2 PM (lunch), gap from 2 PM - 5 PM, reopen 5 PM - 9 PM (dinner)
**FAQ Management**
* Remove regular store hours from FAQs (no longer needed)
* **Keep holiday hours in FAQs** for special scheduling
* The AI automatically uses configured store hours for regular operations
**Consistent Updates**
* Update store hours before holidays or special events
* Keep them in sync with your actual operating schedule
* Review weekly to ensure accuracy
## Next Steps
Add knowledge base content
Customize AI voice
# Voice Configuration
Source: https://docs.maple.inc/voice-core/voice-configuration
Customize your AI voice personality and settings
Customize how your Maple AI sounds and interacts with customers to match your brand personality.
## Voice Selection
### Available Voices
* Male and female options
* Different accents (US, UK, Australian)
* Age variations (younger, mature)
* Energy levels (calm, energetic)
### Choosing Your Voice
Consider:
* Brand personality
* Customer demographics
* Regional preferences
* Type of restaurant
## Personality Settings
### Tone Options
* **Professional**: Formal, polished
* **Friendly**: Warm, conversational
* **Casual**: Relaxed, approachable
* **Enthusiastic**: Upbeat, energetic
### Speaking Style
* Pace (slow, normal, fast)
* Pitch variation
* Emphasis patterns
* Pause timing
## Conversation Settings
### Greeting Customization
* Standard greeting
* Time-based greetings
* Special occasion greetings
* Return customer recognition
### Response Patterns
* Acknowledgment phrases
* Transition words
* Closing statements
* Hold messages
Test different settings with your team before going live.
## Advanced Configuration
### Language settings
Configure which languages your Maple AI supports. English is always enabled. You can add additional languages from the agent settings in your dashboard under **Message → Advanced → Languages**.
| Language | Status |
| ---------------- | --------------------- |
| English | Always on |
| Spanish | Available |
| Mandarin Chinese | Available |
| Cantonese | Beta (limited access) |
| French | Beta (by request) |
When any non-English language is enabled, Maple switches to multilingual mode. In this mode, voice options are limited to **Female Voice** and **Male Voice** to ensure consistent quality across languages. If you previously selected a different voice, it is automatically adjusted.
Enable only the languages you actually need. Recognition and response quality degrade beyond roughly two languages, and
the welcome/greeting message is English-only. For best accuracy, use one primary language plus at most one additional
non-English language.
Multilingual support is in beta. Contact Maple support to enable French for your location or to request other
languages.
### Conversation Flow
* Interruption handling
* Clarification requests
* Error recovery
* Escalation triggers
### Difficult Words (Word Boosters)
Every restaurant has unique vocabulary -- menu items, brand names, cuisine-specific terms -- that can be tricky for the speech-to-text engine to transcribe correctly. The **Difficult Words** feature lets you build a per-store word bank of these terms so the AI recognizes them more accurately during calls.
**Where to find it:**
* **QA Dashboard** -- scroll to the "Difficult Words" card at the bottom of the page (a store must be selected in the navbar)
* **QA Calls sidebar** -- open any call, then click the **Words** tab in the right-hand panel
**How to use it:**
1. Click **+ Add Word** and type the word or phrase (e.g., "focaccia", "pho", "açaí bowl")
2. Press Enter or click the add button to save it
3. The word immediately appears in the table and is linked to the selected store
4. To remove a word, click the trash icon next to it
Review call transcripts regularly. When you spot a word the AI consistently gets wrong, add it to the Difficult Words
list. The fix takes effect on the next call -- no restart needed.
Words are unique per store, so each location can have its own tailored list. Once added, they are automatically sent to the speech engine whenever a new call comes in for that store.
## Testing Your Voice
1. Use preview mode
2. Make test calls
3. Gather team feedback
4. Adjust settings
5. Test again
## Call handoff & transfers
Maple can hand a caller off to your staff in two ways. Which one applies depends on how your line is set up.
### Ring Staff First (passthrough)
The AI rings your staff line first for a number of rings before taking over the call. How many rings — or how long — before the AI picks up is controlled by your phone carrier and physical phone, not a Maple setting. Adjust the ring count with your carrier if you want staff to have more or less time to answer first.
### Transfer to Staff
The AI places an outbound call from your Maple number to your handoff number. If that outbound call isn't answered, it may reach voicemail after roughly 20 seconds (carrier-controlled), which the caller hears as "the restaurant is busy."
To improve transfer reliability:
* Extend your carrier's voicemail trigger time so the handoff line rings longer before voicemail picks up.
* Make sure the handoff line is reachable and answered by a person.
* Enable SMS notifications so staff are alerted to missed transfers.
**Current limitations.** Only the Maple agent number appears in your carrier's call history — Maple cannot forward the
original customer's caller ID, due to telephony regulation. Phone extensions are not supported.
## Call Transfer Settings
### Transfer Timeout
When transferring calls to staff, Maple uses a 25-second timeout to determine if the transfer was successful. If the call isn't answered within this timeframe, it routes back to the AI.
The 25-second timeout is optimized to prevent carrier auto-responses and voicemail systems from marking the call as
complete, which would prevent it from routing back to the AI.
### SMS Notifications for Missed Transfers
When a transferred call isn't answered, Maple automatically sends an SMS notification to alert staff about the missed call.
**Number Priority:**
1. **SMS number** (if configured in dashboard)
2. **Handoff number** (fallback if no SMS number provided)
**Automatic Validation:**
* Maple checks the line type before sending SMS
* Text messages are not sent to landlines
* Only valid mobile numbers receive notifications
Configure your SMS number in the dashboard to ensure staff receive missed call notifications. If no SMS number is
provided, the system will use your handoff number as a fallback.
## Next Steps
* [Get Phone Number](/voice-core/phone/getting-number)
* [Configure SMS](/voice-core/sms-a2p)