eatsy

eatsy Webhooks

Overview

eatsy can send webhook notifications to your business when order events happen. Webhooks let your system receive order updates automatically without polling an API.

To receive webhooks, provide eatsy with an HTTPS webhook URL. eatsy will send a POST request to that URL whenever a subscribed event occurs.

eatsy will also generate and provide your business webhook secret. Your endpoint should use this secret to verify that webhook requests came from eatsy.

Webhook Notifications

Webhook notifications are sent as JSON over HTTPS.

Each notification includes:

  • A top-level event type.
  • The eatsy business ID.
  • The related order ID.
  • Event data in the data object.
  • Request headers that identify the event and help you verify the sender.

Your endpoint should acknowledge receipt with a 2xx response.

Event Types

eatsy currently supports these webhook event types:

Event typeDescription
order.createdAn order was created.
order.paidAn order is paid in full. If the order requires a courier, delivery has been created successfully and assigned before this event is sent. Only orders that meet these requirements are presented to restaurants.
order.refundedAn order payment was refunded.
order.canceledAn order was canceled.

For now, order.paid is the event guaranteed to include the full order object in data.

Request Headers

Every webhook request includes these headers:

Content-Type: application/json
X-eatsy-Webhook-Secret: <your-business-webhook-secret>
X-eatsy-Event-Id: <event-id>
X-eatsy-Event-Type: <event-type>
X-eatsy-Business-Id: <business-id>
HeaderDescription
Content-TypeAlways application/json.
X-eatsy-Webhook-SecretSecret generated by eatsy for your business. Use it to verify the request.
X-eatsy-Event-IdUnique webhook event ID. Use this for idempotency.
X-eatsy-Event-TypeEvent type, such as order.paid.
X-eatsy-Business-Ideatsy business ID associated with the event.

Payload Format

Webhook requests use this top-level JSON shape:

{
  "type": "order.paid",
  "business_id": "7e15147b-89b0-4abe-8a29-5bf7a9acb525",
  "order_id": "41282d6d-f3b2-43a0-be66-daf16decebf4",
  "data": {}
}
FieldDescription
typeWebhook event type.
business_ideatsy business ID.
order_idRelated eatsy order ID.
dataEvent data. For order.paid, this is the full order object.

Example Order Paid Payload

This example shows the maximum current shape of an order.paid payload.

{
  "data": {
    "items": [
      {
        "image": "https://geuhlojitrsdezslcoxx.supabase.co/storage/v1/object/public/products/7e15147b-89b0-4abe-8a29-5bf7a9acb525/1766618561109-y0bit7i-fries.jpeg",
        "options": {
          "date": [
            {
              "name": "DATE OPTION",
              "value": "2026-05-26"
            }
          ],
          "text": [
            {
              "name": "TEXT OPTION",
              "value": "value of text option"
            }
          ],
          "number": [
            {
              "name": "NUMBER OPTION",
              "value": 1234
            }
          ],
          "checkbox": [
            {
              "name": "CHECKBOX",
              "choices": [
                {
                  "price": 1000,
                  "choice": "CHOICE 1"
                },
                {
                  "price": 0,
                  "choice": "CHOICE 2"
                }
              ]
            },
            {
              "name": "CHECKBOX with quantity",
              "choices": [
                {
                  "price": 1000,
                  "choice": "choice 1",
                  "quantity": 2
                }
              ]
            }
          ],
          "selection": [
            {
              "name": "SELECTION OPTION",
              "choice": {
                "price": 1000,
                "choice": "CHOICE 1"
              }
            },
            {
              "name": "Selection with quantity",
              "choice": {
                "price": 1000,
                "choice": "choice 1",
                "quantity": 4
              }
            }
          ]
        },
        "quantity": 2,
        "total_price": 3000,
        "product_variant_name": "Sandwich - Fries"
      },
      {
        "image": null,
        "options": {},
        "quantity": 1,
        "total_price": 1000,
        "product_variant_name": "Producto 1"
      }
    ],
    "client": {
      "email": "asolmon88@gmail.com",
      "last_name": "",
      "first_name": "Ariel",
      "phone_number": "+50683117124"
    },
    "order_id": "41282d6d-f3b2-43a0-be66-daf16decebf4",
    "created_at": "2026-05-06T05:21:43.774078+00:00",
    "receipt_url": null,
    "order_status": "pending",
    "order_options": [
      {
        "type": "select",
        "value": {
          "price": 0,
          "choice": "Coca cola"
        },
        "question": "Coca cola gratis incluida"
      }
    ],
    "tracking_link": "https://delivery.uber.com/cr/orders/17bb6af2-4511-457e-85a5-28a6d178d36c?tenancyOverride=uber%2Ftesting%2Fdirect%2F1b3fa1f7-10c6-56ce-9808-6cb1e6f2b7de",
    "delivery_price": 0,
    "products_price": 15000,
    "delivery_method": {
      "uid": "a926c50e-b6db-407c-b949-1422d8d4ecd8",
      "name": "Express",
      "require_courier": true
    },
    "pickup_ready_dt": "2026-05-06T05:42:10.094+00:00",
    "uber_customer_id": "1b3fa1f7-10c6-56ce-9808-6cb1e6f2b7de",
    "uber_delivery_id": "del_F7tq8kURRX6FpSim0XjTbA",
    "discount_breakdown": {
      "code": "DESCUENTO",
      "title": "Descuento 1",
      "ends_at": null,
      "starts_at": "2026-02-19T14:51:45+00:00",
      "applies_to": "orders",
      "value_type": "percent",
      "discount_id": "1c0b615b-1867-4da5-a5a1-f7eb82698d01",
      "value_amount": 15,
      "location_scope": "all",
      "discount_amount": 2250,
      "eligible_subtotal": 15000,
      "order_total_after_discount": 12750,
      "order_total_before_discount": 15000
    },
    "human_order_number": 236,
    "pickup_deadline_dt": "2026-05-06T05:52:10.094+00:00",
    "delivery_created_at": "2026-05-06T05:22:10.094+00:00"
  },
  "type": "order.paid",
  "order_id": "41282d6d-f3b2-43a0-be66-daf16decebf4",
  "business_id": "7e15147b-89b0-4abe-8a29-5bf7a9acb525"
}

Order Data Fields

The data object for order.paid contains the order information your business can use for fulfillment.

FieldDescription
data.order_idUnique eatsy order ID.
data.human_order_numberHuman-friendly order number shown to the business.
data.created_atOrder creation timestamp in ISO 8601 format.
data.order_statusCurrent order status.
data.products_priceTotal price of products before delivery fees.
data.delivery_priceDelivery fee charged for the order.
data.order_optionsOrder-level options selected by the customer.
data.clientCustomer contact information.
data.delivery_methodDelivery method selected for the order.
data.itemsProducts and variants included in the order.
data.tracking_linkDelivery tracking URL, when available.
data.uber_delivery_idUber delivery ID, when the order uses Uber delivery.
data.uber_customer_idUber customer ID, when available.
data.pickup_ready_dtEstimated time when the order should be ready for pickup.
data.pickup_deadline_dtPickup deadline timestamp.
data.delivery_created_atTimestamp when delivery was created.
data.discount_breakdownDiscount metadata and calculated discount totals, when a discount applies.
data.receipt_urlReceipt URL, when available.

Item Fields

Each object in data.items represents a product variant in the order.

FieldDescription
imageProduct image URL, or null.
optionsProduct option groups selected by the customer.
quantityQuantity ordered.
total_priceItem price value included in the order payload.
product_variant_nameProduct and variant display name.

Item Option Groups

Item options can include these groups:

Option groupDescription
dateDate-based option answers.
textText option answers.
numberNumeric option answers.
checkboxOne or more selected choices.
selectionA single selected choice.

Some choices can include quantity when the option supports quantities.

Webhook Security

eatsy generates a unique webhook secret for your business.

Every webhook request includes the secret in this header:

X-eatsy-Webhook-Secret: <your-business-webhook-secret>

Your endpoint must compare this header with the webhook secret provided by eatsy. If the value does not match, reject the request.

Example:

const expectedSecret = process.env.EATSY_WEBHOOK_SECRET;
const receivedSecret = request.headers.get("X-eatsy-Webhook-Secret");

if (receivedSecret !== expectedSecret) {
  return new Response("Unauthorized", { status: 401 });
}

The webhook secret does not protect your endpoint automatically. It only protects your endpoint if your application validates it before processing the request.

Use X-eatsy-Event-Id to make your webhook handler idempotent. If your system receives the same event ID more than once, it should avoid processing the same event twice.

Expected Response

Return any 2xx HTTP response when your service has successfully received the webhook.

Examples:

200 OK
202 Accepted
204 No Content

Your endpoint should return quickly. If processing the webhook requires slow work, acknowledge the request first and process the work asynchronously.

Do not return a 2xx response if your service did not safely receive the event.

Timeouts And Failed Deliveries

eatsy waits up to 10 seconds for your endpoint to respond.

A webhook delivery is considered failed if:

  • Your endpoint returns a non-2xx HTTP status.
  • Your endpoint does not respond within 10 seconds.
  • Your endpoint cannot be reached.

Automatic retry behavior is currently in the works.

Set Up Your Webhook URL

To enable webhooks, provide eatsy with:

  • Your HTTPS webhook endpoint URL.
  • Any different endpoint URLs you want to use for specific locations.
  • Whether you need the location ID included in the webhook payload.
  • The technical contact responsible for maintaining the endpoint.

eatsy will generate and provide your business webhook secret.

Test Your Webhook

To test your webhook integration:

  1. Configure your webhook endpoint URL with eatsy.
  2. Confirm your endpoint accepts POST requests with a JSON body.
  3. Confirm your endpoint validates X-eatsy-Webhook-Secret.
  4. Create or pay a test order that should produce an order.paid event.
  5. Confirm your endpoint receives the request.
  6. Return a 2xx response to acknowledge the webhook.

For debugging, you can temporarily use a request capture tool to inspect the full request body and headers. Replace the test URL with your production webhook URL before going live.

Troubleshooting

ProblemWhat to check
No webhook receivedConfirm the webhook URL is correct, uses HTTPS, and is enabled for the expected event type.
Webhook received but rejectedConfirm your endpoint is reading X-eatsy-Webhook-Secret and comparing it with the secret provided by eatsy.
Event received more than onceUse X-eatsy-Event-Id to make processing idempotent.
Delivery marked failedConfirm your endpoint returns a 2xx response within 10 seconds.
Missing order detailsFor now, only order.paid is guaranteed to include the full order object in data.