Use Cases

Papaya’s API will continue to evolve with innovative capabilities that unlock new possibilities for partners and merchants. The initial focus is on digital ordering, reservation integrations, access to order data for analytics and reporting, and inventory management systems.

Setup

The API is scoped to a Papaya outlet, which represents an individual restaurant, shop, or branch at a specific physical location. In Papaya’s structure, an outlet sits under a merchant — the top-level entity that groups together multiple outlets.

To begin using the API, you must first Enable Open API for a specific outlet via the merchant dashboard: https://merchant.papaya.co.th/settings/openapi

Once enabled, you can generate one or more API keys, each linked to a specific use case along with a corresponding webhook URL.

Access tokens are shown only once. Please copy and store them securely. If forgotten, you’ll need to delete and recreate the API key for that use case.

Digital Ordering

Integrate food-delivery aggregators or other online ordering platforms with Papaya’s POS.

Flow

  1. Credential & Channel Setup

    1. In the Papaya merchant dashboard, create an API key with the use case set to “Digital Ordering”, and securely store the generated Bearer token for authentication.
    2. Under Channels in the merchant dashboard, register your ordering platform as a channel of type “Partner” (e.g. Grab, LINEMAN). This allows it to be retrieved via the GET /api/v1/channels endpoint.
  2. Sync Menu

    1. Fetch the current menu for that channelType:

      GET /api/v1/menus?channelType={channelType}
      
    2. Noting that for channelType = partner, you should also include the partnerChannel query parameter with the appropriate string value (e.g. grab) to ensure partner-specific menu overrides are applied.

  3. Create Order

    1. When the ordering platform receives a new order, forward it into Papaya:

      POST /api/v1/orders
      
      {
        "channelId": "{channel.id}",
        "partnerInfo": {
          "partnerChannel": "grab",
          "orderId": "GF-123"
        },
        "items": [
          {
            "customerName": "Pim",
            "menuItemId": "{menuItem.id}",
            "quantity": 2,
            "options": [
              {
                "optionId": "{option.id}",
                "quantity": 1
              }
            ]
          }
        ],
        "payments": [
          {
            "offlineMethod": "card",
            "amount": 100,
            "customerName": "Pim",
            "externalId": "stripe-123",
            "currency": "THB",
            "created": "2025-06-22T08:55:26.169Z"
          }
        ]
      }
      
  4. Track & Fulfill

    1. Receive live updates via your configured webhook (recommended)
    2. or, poll the order using GET /api/v1/orders/:id
  5. To Cancel an Order

    Use the update order endpoint to change the order status to cancelled when an order is no longer proceeding.

    PUT /api/v1/orders/:id
    
    {
      "status":"cancelled"
    }
    

Key Endpoints

Endpoint Method Description
/channels GET List available channels
/menus GET Retrieve menu for a given channelType
/orders POST Create a new order
/orders/:id GET Fetch order details & status
/orders/:id PUT Cancel an order
Webhook URL POST Receive order status notifications

Reservations

Connect a restaurant booking system to initiate orders on the POS from reservations and walk-ins, and receive real-time order updates.

Flow

  1. Credential & Channel Setup

    1. In the Papaya merchant dashboard, create an API key with the use case set to “Reservations”, and securely store the generated Bearer token for authentication.
    2. In the merchant dashboard under Channels, create a channel for each table, ensuring each is set to type “Dine-in”. All channels can then be retrieved via the GET /api/v1/channels endpoint.
  2. Open an Order (Table)

    1. When you mark a customer as arrived on your reservation platform, your system calls:

      POST /api/v1/orders/reservations
      
      {
        "channelId": "{channel.id}",
        "guestCount": 4,
        "partnerReservationInfo": {
          "partnerName": "Reservation App Name",
          "reservationId": "res-123",
          "firstName": "John",
          "lastName": "Doe",
          "email": "john.doe@example.com",
          "phoneNumber": "+66922801111"
        },
        "payments": [
          {
            "offlineMethod": "card",
            "amount": 100,
            "currency": "THB",
            "externalId": "stripe-123",
            "created": "2025-06-22T08:55:26.169Z"
          }
        ]
      }
      
    2. This creates an order in Papaya POS linked to the reservation. A payments array is optional and should be included if a deposit has already been paid.

    Only channels with type dine-in can be opened using the POST /orders/reservations endpoint.

  3. Update an Order

    1. When the reservation changes on your platform — host moves the table, marks the booking cancelled, edits the party size, or updates guest contact info — call:

      PUT /api/v1/orders/reservations/{id}
      
      {
        "channelId": "{channel.id}",             // move table
        "status": "cancelled",                   // close the order
        "guestCount": 6,
        "partnerReservationInfo": {
          "firstName": "Jane",
          "email": "jane@example.com",
          "note": "VIP — window seat"
        }
      }
      
    2. All fields are optional; send only what’s changing. Notes:

      • status: "cancelled" cannot be combined with other fields.
      • partnerName and reservationId are immutable.
      • Only the API key that created the order can update it.
  4. Listen for Order Updates

    1. After initiating an order, your reservation platform will receive order update notifications via the Webhook URL configured when creating the API key in the merchant dashboard.

    2. Four events can trigger a reservation order update:

      1. order.totalsUpdated — order totals have changed
      2. order.statusUpdated — order status has changed (e.g. from open to cancelled)
      3. order.channelUpdated — the order was moved between tables
      4. order.guestCountUpdated — guest count has changed
    3. Use the GET /api/v1/orders/:id endpoint to fetch the latest order details and respond as needed based on your platform’s business logic.

    Webhook notifications will only be sent for orders initiated from the reservation platform.

  5. Listen for Channel Updates

    1. When a merchant updates their channel (table) configuration in the merchant dashboard, those changes are published to reservation partners.
    2. You will receive a channels.published notification via the Webhook URL.
    3. Upon receiving this event, call GET /api/v1/channels to retrieve the latest channel (table) configuration data.

Key Endpoints

Endpoint Method Description
/channels GET List available channels
/orders/reservations POST Open a reservation-linked order in Papaya
/orders/reservations PUT Update a reservation-linked order
/orders/:id GET Fetch latest order details
Webhook URL POST Receive postbacks for reservation order updates and channel / table config changes

Order Data

Get complete sales and order data from Papaya’s POS to simplify reporting, reconciliation, and performance tracking.

Flow

  1. Credential Setup

    1. In the Papaya merchant dashboard, create an API key with the use case set to “Order Data”, and set a webhook URL for receiving order updates.
    2. Securely store the generated Bearer token for authentication.
  2. Listen for Order Completion (Recommended)

    1. When orders are placed through Papaya’s POS, regardless of source, you’ll receive real-time updates via your configured webhook URL. These updates are sent as lightweight “thin” events containing only the event name and Order ID.

    2. For the Order Data use case, only two event types are sent from the Order status webhook:

      1. order.complete — the order was successfully completed and paid
      2. order.cancelled — the order was cancelled, either before or after payment

      These two events represent the final, permanent state of an order.

      POST {webhook_url}
      
      {
        "id": "01K7KAT54KQ6544MKY9G5TTEWG",
        "event":"order.complete",
        "updatedAt": "2025-10-10T08:55:26.169Z"
      }
      
    3. Use the GET /api/v1/orders/:id endpoint to retrieve the latest order details for your integration or reporting needs.

      We recommend this webhook-driven approach as your primary integration pattern. It ensures you always have the latest data without unnecessary polling.

    You may receive multiple order updates, as orders can be cancelled after completion or reopened and modified before being completed again. However, merchants should always transition orders back to either a complete or cancelled state.

  3. Retrieve Orders by Date Range (Alternative)

    If you need to reconcile, backfill, or retrieve orders in bulk, use the GET /api/v1/orders endpoint to query orders within a specified date range.

    • Filter by status (complete, cancelled) via the status query parameter. Defaults to both.
    • Maximum date range is 31 days.
    • Results are paginated with up to 25 orders per status per page using cursor-based pagination.
    • Each order includes the full payload (items and payments), matching the GET /api/v1/orders/:id response shape.
    GET /api/v1/orders?from=2026-01-01T00:00:00Z&to=2026-01-31T23:59:59Z
    

    This endpoint is best suited for reconciliation and backfilling — not as a replacement for webhooks. Excessive polling may result in rate limiting (5 requests/second).

Key Endpoints

Endpoint Method Description
/orders/:id GET Fetch latest order details
/orders GET Fetch orders by date range
Webhook URL POST Receive order.complete and order.cancelled notifications

Inventory Management

Sync Papaya POS menus and real-time orders to inventory management systems. Automatically update stock levels and ingredient usage as orders are finalised.

Flow

  1. Credential Setup

    1. In the Papaya merchant dashboard, create an API key with the use case set to “Inventory Management”, and set a webhook URL for receiving menu and order updates.
    2. Securely store the generated Bearer token for authentication.
  2. Listen for Menu Changes

    1. When the merchant publishes menu updates (new items, pricing changes, availability toggles), you’ll receive a webhook notification — menus.published:

      POST {webhook_url}
      
      {
        "event":"menus.published",
        "updatedAt": "2025-10-10T08:55:26.169Z"
      }
      
    2. Use the GET /api/v1/menus endpoint to retrieve the latest POS menu data and sync with inventory system.

  3. Listen for Order Completion (Recommended)

    1. When orders are placed through Papaya’s POS, you’ll receive real-time updates via your configured webhook URL. These updates are sent as lightweight “thin” events containing only the event name and Order ID.

    2. For the Inventory Management use case, only two event types are sent from the Order status webhook:

      1. order.complete — the order was successfully completed and paid
      2. order.cancelled — the order was cancelled, either before or after payment

      These two events represent the final, permanent state of an order.

      POST {webhook_url}
      
      {
        "id": "01K7KAT54KQ6544MKY9G5TTEWG",
        "event":"order.complete",
        "updatedAt": "2025-10-10T08:55:26.169Z"
      }
      
    3. Use the GET /api/v1/orders/:id endpoint to retrieve the latest order details, ensuring the inventory system has all the necessary sales context for ingredient usage, etc.

      We recommend this webhook-driven approach as your primary integration pattern. It ensures your inventory system always reflects the latest order state without unnecessary polling.

    You may receive multiple order updates, as orders can be cancelled after completion or reopened and modified before being completed again. However, merchants should always transition orders back to either a complete or cancelled state.

  4. Retrieve Orders by Date Range (Alternative)

    If you need to reconcile inventory adjustments or backfill order data for a specific period, use the GET /api/v1/orders endpoint to query orders within a date range.

    • Filter by status (complete, cancelled) via the status query parameter. Defaults to both.
    • Maximum date range is 31 days.
    • Results are paginated with up to 25 orders per status per page using cursor-based pagination.
    • Each order includes the full payload (items and payments), matching the GET /api/v1/orders/:id response shape.
    GET /api/v1/orders?from=2026-01-01T00:00:00Z&to=2026-01-31T23:59:59Z
    

    This endpoint is best suited for reconciliation and backfilling — not as a replacement for webhooks. Excessive polling may result in rate limiting (5 requests/second).

Key Endpoints

Endpoint Method Description
/menus GET Retrieve menus for a given channelType
/orders/:id GET Fetch individual order details
/orders GET Fetch orders by date range
Webhook URL POST Receive menus.published, order.complete and order.cancelled notifications

Accounting

Combine sales and purchase costs to feed an accounting system.

Accounting is not a separate use case. Create the API key with the use case set to “Order Data” — one key reads both halves:

  • Sales — completed and cancelled orders, via the webhooks and endpoints in Order Data above.
  • Purchases — goods receipts, the supplier bills merchants record against inventory, via GET /api/v1/inventory/goods-receipts.

Without the purchases half, an accounting integration only sees revenue.

Flow

  1. Credential Setup

    Follow the Order Data setup above. The same Bearer token authenticates the goods receipts endpoint — the merchant and outlet scope is read from the key.

    If “Order Data” does not appear in the use case dropdown, the outlet’s plan does not include Open API data access. Contact your Papaya representative.

  2. Poll for Goods Receipts

    When stock arrives at an outlet, staff record a goods receipt in Papaya — either by uploading the supplier invoice (photo or PDF) for automatic extraction, or by keying the lines in manually. A completed goods receipt is the POS’s record of a supplier bill: what was delivered, from which supplier, at what cost, and with what tax.

    Goods receipts do not emit webhooks. Query them on a schedule — nightly is enough for most accounting workflows.

    GET /api/v1/inventory/goods-receipts?from=2026-01-01T00:00:00Z&to=2026-01-31T23:59:59Z
    

Query Rules

  • from and to are required, in RFC 3339 format, and filter on the created timestamp — when the receipt was recorded in Papaya, not the supplier’s delivery date.
  • Maximum date range is 31 days.
  • Results are ordered oldest-first by created, up to 25 receipts per page. A page may return fewer than 25 and still carry a next cursor — always follow the cursor until it is null.
  • status accepts a comma-separated list (draft, completed, cancelled, partiallyReceived) and defaults to completed — real bills only. Leave the default in place for accounting: drafts are unconfirmed and their amounts still change.
  • supplierId filters to a single supplier.
  • Rate limit is 5 requests/second per API key, shared with the /orders endpoints.

Field Mapping

Field Use it as
deliveryDate The bill date in your accounting system
created When Papaya recorded the receipt. The from/to window filters on this — use it for incremental syncs
goodsReceiptNumber Reference number (e.g. GR-0001)
supplier Vendor — supplierId, name, and address, snapshotted when the receipt was recorded
items[].totalPrice Line amount. Authoritative for accounting
items[].discountAmount Per-line supplier discount. The line nets to totalPrice - discountAmount
items[].taxRate*, items[].taxAmount The tax rate snapshot applied to that line at receipt time — taxRateName, taxRate, taxRateKind. taxRate is a decimal (0.07 = 7%)
items[].pricePerUnit Unit cost per inventoryUom. A derived rate rounded to 6 decimal places — do not reconstruct line totals from it
discount Document-level supplier discount (the invoice-footer “less discount” line). Allocated across lines pro-rata by net line value when computing each line’s tax
shippingFee Freight or delivery charge. Never discounted and never taxed
tax Total tax on the receipt
total Amount payable
isTaxInclusive Whether each line’s totalPrice already includes tax — this determines how total is composed

Reconciling Totals

All amounts are in the outlet’s currency. Both discount levels come off the goods value before tax, and never off the shipping fee. A line’s tax base is its net (totalPrice - discountAmount) less its pro-rata share of the document discount.

  • When isTaxInclusive is false: total = totalPrice - line discounts - discount + tax + shippingFee
  • When isTaxInclusive is true: total = totalPrice - line discounts - discount + shippingFee (tax is already inside the line prices)

Header amounts are rounded to 2 decimal places, so summed line amounts may differ from the header by up to 0.01. Post the header total as the bill amount and let your accounting system absorb the rounding on the lines.

Older receipts recorded before totals were captured may omit tax and total. Treat these fields as optional and fall back to the line items.

Things to Know

  • Goods receipts are outlet-scoped. Each API key covers one outlet — run one sync per outlet. Passing a merchantId or outletId that does not match the key returns 403.
  • Suppliers come from the receipt, not a directory. Each receipt carries its own supplier snapshot. The GET /inventory/suppliers and GET /inventory/products endpoints are not available to outlet API keys — build your vendor mapping from the supplier.supplierId values you see on receipts.
  • Creating goods receipts is not available to outlet API keys. POST /api/v1/inventory/goods-receipts is reserved for Papaya’s invoice-import flows. Goods receipts are recorded by the merchant in the POS or dashboard.
  • Credit notes are not exposed via the API. Supplier returns and credits raised against a goods receipt in Papaya will not appear in this endpoint. Handle them in your accounting system directly.
  • A receipt can change after you have read it. A completed receipt can later be cancelled, or a partiallyReceived one completed. Re-poll a trailing window (e.g. the last 7 days) on each run and update bills you have already posted, keying on the goods receipt id.

Key Endpoints

Endpoint Method Description
/inventory/goods-receipts GET Fetch goods receipts by date range (purchase costs)
/orders GET Fetch orders by date range (sales)
/orders/:id GET Fetch latest order details
Webhook URL POST Receive order.complete and order.cancelled notifications