Filldv1

Filld Developer Documentation

SCN Portal Integration for Evergreen

Integrate your SCN platform with Evergreen Kosher Market — send orders that Evergreen's own shoppers pick, check out on your account and deliver, follow every step to the doorstep, and get an itemized receipt. Check live delivery windows when you want them.

Introduction

SCN Portal Integration for Evergreen — the Partner Slots API, built and operated by Filld — gives SCN platforms programmatic access to Evergreen Kosher Market's real delivery capacity. Check which delivery windows are available for a customer's address and book one — a single call — when the order is placed, so every platform draws from the same capacity pool and customers are never promised a time the store cannot honor.

Orders you send go into Evergreen's picking queue. Our shoppers pick them in the store at regular shelf prices. When picking is finished, the order is checked out at the register on your account and delivered. You can follow each step, see the delivery photos and signature, and get an itemized receipt of what was picked and billed.

Filld operates the platform and issues your API keys; the API fronts Evergreen's stores and delivery operation.

All slot dates and windows are store-local wall times (America/New_York). orderBy and every other timestamp are ISO 8601 UTC instants.

A full sandbox is available: test keys run the entire API — real windows, real validation — with zero real-world impact. See Sandbox & Testing.

Base URL

Everything lives under one base URL:

Base URL
https://api.filld.dev/api/v1

Order endpoints (/orders, /orders/id/{orderNumber}, /orders/external/{externalOrderId}) and delivery endpoints (/delivery/availability, /delivery/reservations) all live under it.

Authentication

Authenticate every request with an API key sent in the x-api-key header. Keys are issued per organization by Filld and begin with evg_live_. Requests without a valid key receive 401 unauthorized. Test keys (evg_test_) work in the same header and run the full API against the sandbox — see Sandbox & Testing.

Header
x-api-key: evg_live_XXXXXXXXXXXXXXXX

Keep your key server-side

Never embed your API key in a browser or mobile app. Route all Partner Slots API calls through your own backend.

Your Evergreen key is the only API credential you need. When you send an order, also send the X-Customer-Pin header: the PIN of your on-account customer (customerId). Every order is billed on account to that customer when it is checked out after picking. Evergreen keeps the PIN encrypted until then and deletes it right after.

Sandbox & Testing

API keys come in two modes, sent in the same x-api-key header: live keys begin with evg_live_; test keys begin with evg_test_ and are issued the same way by Filld, from the same organization. A test-key request runs the entire API identically — same endpoints, same validation, real zones, real windows, real order-by deadlines, and realistic slot_unavailable responses when a window is genuinely full — but with zero real-world impact:

  • Reservations. Sandbox reservations never consume real capacity, and real traffic never blocks on them. They follow the same lifecycle — immediate bookings, opt-in holds, cancel, expire.
  • Orders. Orders created with a test key are not actually placed or fulfilled — you receive a TEST--prefixed order number and can exercise the full flow: 201 with an empty body, a Location: /orders/id/TEST-48210937 header, and the extra header x-evergreen-sandbox: true.
  • Failure simulation. Include the string simulate=pos_error anywhere in the order's note field — the sandbox returns a 400 error in the standard problem+json format so you can exercise failure handling; any capacity taken by the call is released, as with a real failure.
  • Order status. GET /orders/id/{orderNumber} for a TEST- id returns a stub order: { id, externalOrderId, status: "OrderEntered", pickupDeliveryTime, items: [], sandbox: true }.
  • Tracking & editing. Tracking works in sandbox but stays at sent_to_pos, because sandbox orders are not picked and have no receipt. Editing is live-only: sandbox orders are treated as sent immediately, so PATCH /orders/id/… returns 409 order_not_editable.
  • Isolation. Test and live data are fully isolated: a test key sees only reservations and orders created by test keys — cross-mode lookups return 404 — and vice versa.

Integrate and run CI against your test key, then switch the key — one environment variable — to go live.

Request
curl -X POST "https://api.filld.dev/api/v1/orders" \
  -H "x-api-key: evg_test_XXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "customerId": "18452",
    "orderMethod": "Delivery",
    "pickupDeliveryTime": "2026-07-07T10:00:00",
    "externalOrderId": "cart_88213",
    "items": [
      { "productCode": "412009", "quantity": 2, "unitPrice": 4.99 }
    ],
    "deliveryAddress": {
      "name": "Chaim Brachfeld",
      "phoneNumber": "8455550142",
      "address": {
        "addressLine1": "12 Main St",
        "city": "Monsey",
        "state": "NY",
        "zipCode": "10952"
      }
    }
  }'
Response — 201 Created (simulated, empty body)
HTTP/1.1 201 Created
Location: /orders/id/TEST-48210937
x-evergreen-sandbox: true

Sandbox availability is real availability

If a window shows as full in the sandbox, it really is full — pick another window rather than treating it as a test artifact.

Content Type

Send request bodies as JSON with the Content-Type: application/json header. All responses are returned as JSON.

Rate Limiting

Requests are limited to 120 per minute per organization by default. Requests over the limit receive 429 rate_limited. Back off and retry after a short delay. Contact Filld if your integration needs a higher limit.

Reserving a Slot

Optional for orders

You do not need a reservation to send an order. POST /orders accepts the requested date and time directly (see Sending Orders). Reservations still work if you use them: pass reservationId on the order.

Reserving books the slot — one call, done. POST /delivery/reservations returns a reservation with status confirmed; the slot is consumed until the delivery date passes. Reserve at the moment the customer places the order (right before you send it to the POS), and you never need to touch the reservation again.

  1. Customer enters their address — check availability (POST /delivery/availability).
  2. Customer picks a window and places the order — reserve the slot (POST /delivery/reservations), then send the order to the POS exactly as you do today.
  3. Optional: attach your POS order number via POST /reservations/{id}/confirm; call DELETE if your order failed.

Important

Reserve when the order is placed, not when the slots are displayed — a reservation consumes real capacity immediately.

One call, no availability lookup

Already know the time your customer picked? Skip availability entirely: send the address, the time, and (optionally) your POS order number — one call, booked. Pass time instead of slotId; the reservation is booked into whichever offered window covers the requested time (Eastern; an offset-less time is taken as Eastern wall time).

Request
curl -X POST "https://api.filld.dev/api/v1/delivery/reservations" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "time": "2026-07-09T10:30:00",
    "posOrderRef": "15009999",
    "address": {
      "street": "12 Main St",
      "city": "Monsey",
      "state": "NY",
      "zip": "10952"
    }
  }'
Response — 201 Created
{
  "reservationId": "res_4b1e77c2a90f",
  "status": "confirmed",
  "slot": {
    "slotId": "slot_UGsxNDQzfDIwMjYtMDctMDk",
    "date": "2026-07-09",
    "window": { "start": "09:00", "end": "12:00" },
    "label": "Thu, Jul 9 · 9:00 AM – 12:00 PM"
  },
  "zone": { "id": "zone_mnsy01", "name": "Monsey" },
  "expiresAt": null,
  "customerRef": null,
  "partnerOrderRef": null,
  "posOrderRef": "15009999",
  "createdAt": "2026-07-03T14:15:00.000Z",
  "confirmedAt": "2026-07-03T14:15:00.000Z",
  "cancelledAt": null
}

The response tells you the actual delivery window the time landed in (slot.window / slot.label— here 10:30 resolved to the 9:00 AM–12:00 PM window) — display that window to the customer, not the raw time.

Optional: checkout-start holds

To grab capacity when checkout starts instead, pass ttlMinutes (5–120) on the reserve call. The reservation is created as held with expiresAt set; confirm it (POST /reservations/{id}/confirm) before it lapses, or the hold expires automatically and the capacity is released. Confirming after it lapses returns 409 reservation_expired — reserve again.

Reservation states

  • confirmed — booked. The default: reserving without ttlMinutes returns confirmed immediately, with expiresAt: null.
  • held — opt-in hold mode only: capacity is taken, but the reservation must be confirmed before expiresAt.
  • cancelled — released via DELETE, e.g. when the customer cancels the order.
  • expired — an opt-in hold that lapsed without confirmation. Cannot be confirmed — reserve again.

Sending Orders

The Orders API uses the same request shape as the POSwithLogic create-order API. Set your integration's base URL to https://api.filld.dev/api/v1, use your Evergreen x-api-key, and send X-Customer-Pinwith your on-account customer's PIN. The paths, request body, 201 + Location response and RFC 7807 problem+json errors are the same.

What happens to an order

  1. Received.The order goes into Evergreen's picking queue at the store that serves the address. It does not go straight to the POS.
  2. Picked. Our shoppers pick it in the store. By-weight items are weighed. Out-of-stock items may be substituted (see below).
  3. Checked out on your account. When picking is finished, the order is entered in the POS as picked. It is checked out on account (OnAccount) to your customerId, authorized with your PIN. The recipient's name, phone and address go on the order only as delivery details.
  4. Delivered. The order is labeled and delivered. Delivery photos, the signature and the proof-of-delivery link appear in tracking.

Pricing

Every line is billed at the fulfilling store's regular shelf price. Sale prices, multi-buy ("2 for") and case prices are never applied, and nothing is added on top. The unitPrice / totalPrice you send are kept for reference only; they are not used for billing. By-weight lines (unitOfMeasure: "Lbs") are billed by the weight actually picked. The receipt shows exactly what was billed.

Items

productCodeis the item's barcode or item code (PLU), and it must be an item the fulfilling store carries. If any code is not, the whole order is rejected with 422 unknown_items, which lists the codes. Nothing is created; fix the codes and send the order again.

Substitutions

If an item is out of stock, the shopper may substitute a similar item at the same price or cheaper (at most 5% more). The recipient is not contacted, and Evergreen never texts or emails the recipient. Substitutes and items not found are listed on the receipt, with the substitute's code and name.

Delivery date and window

pickupDeliveryTime is the requested delivery date and time (Eastern; a time without an offset is taken as Eastern wall time). Slots are not booked and capacity is not checked: the order is accepted for the date and time you send. We only check three things:

  • the address is inside our delivery area, otherwise 422 address_not_covered;
  • the date is not in the past, otherwise 422 invalid_delivery_date;
  • the time (and deliveryWindow, if sent) is valid, otherwise 400 invalid_request.

The order goes into the delivery window that covers the requested time. If no window covers it, it goes into the next window later that day. If there is none, it is accepted as requested and you get an x-evergreen-warning header (no_matching_window). To name the window yourself, send "deliveryWindow": { "start": "09:00", "end": "12:00" }. A reservationIdis optional; if you send one, the order uses that reservation's window. Always show the customer the window, never the scheduled time.

Responses

A successful create returns 201 Created with an empty body and a Location: /orders/id/{orderNumber} header. The order number is your Evergreen reference (e.g. SCN1254); it is the number the store uses and it never changes. Other response headers: x-evergreen-delivery-time, x-evergreen-store, x-evergreen-window (YYYY-MM-DD HH:MM-HH:MM), x-evergreen-reservation-id (when you sent one) and x-evergreen-sandbox. Sending the same externalOrderId twice returns 409 duplicate_order, and no second order is created.

Optional Evergreen extensions

deliveryWindow (name the window yourself), reservationId (use a reserved slot), store (pickup orders only, e.g. "uptown") and priority (1 | 2 | 3, 1 = highest; higher-priority orders are picked first). All are optional.

Pickup orders

Send orderMethod: "Pickup" (or omit deliveryAddress) and optionally set store. They are picked the same way.

Order Tracking

Every order has a status that moves forward as the order goes through the store:

accepted → received → picking_started → picking_finished → sent_to_pos → checked_out → label_created → out_for_delivery → delivered (plus cancelled)

  • accepted: held for review. This only happens if Evergreen set your organization's orders to be held. The order can be edited only in this state.
  • received: in Evergreen's picking queue.
  • picking_started: a shopper is picking it.
  • picking_finished: picked and packed.
  • sent_to_pos: entered in the POS as picked.
  • checked_out: invoiced on your account; invoiceNumber is set and the receipt (what was charged) is ready.
  • label_created: the delivery label was made.
  • out_for_delivery: a driver is on the way; eta, driver and trackUrl are set.
  • delivered: done. deliveredAt is set, plus photoUrl, photo2Url, signatureUrl, proofUrl and receiptUrl when the driver captured them.

timeline lists every step the order reached, each with its time. Picking steps show right away. The checkout and delivery steps are checked every few minutes, so expect a delay of up to about 5 minutes.

Polling

Poll POST /api/v1/orders/batch with the ids of your open orders, up to 200 per call, every few minutes. Drop an order from your list once it is delivered or cancelled. Polling more often than once a minute gains nothing. GET /api/v1/orders?since=… returns only the orders that changed since your last poll. The per-order lookups (/orders/id/{orderNumber}, /orders/external/{externalOrderId}) return the same tracking plus the order's lines and, once it is checked out, the receipt.

Receipt

Once the order is checked_out(receiptReady: true), the order detail has a receipt object: what the register actually charged, read back from the POS order. Each line has the code, description, quantity (pounds on a weighed line), unit price and line total, next to what was ordered when it matches. Items not charged (not found) are listed separately, then your account fees, the subtotal and the total. Its pdfUrl is a printable page (Get a Receipt).

Integration Flow

Send orders (recommended)

  1. Set your integration's base URL to https://api.filld.dev/api/v1 and use your Evergreen x-api-key.
  2. When the order is placed, send POST /orders with your on-account customerId, the X-Customer-Pinheader, the items, the recipient's deliveryAddress and the requested pickupDeliveryTime. No reservation is needed.
  3. Store the order number from the Location header.
  4. Poll POST /orders/batch with your open order numbers every few minutes until each one is delivered.
  5. When receiptReady is true, read the receipt from GET /orders/id/{orderNumber} or print it from its pdfUrl.

Showing delivery windows (optional)

To show customers our real windows and order-by deadlines, call POST /delivery/availabilitywith their address, and send the window they pick as the order's pickupDeliveryTime (or deliveryWindow). You can also POST /delivery/reservations and pass the reservationId on the order, but you do not have to.

Endpoints

All endpoints live under the base URL. Every request requires the x-api-key header, and reservation endpoints operate only on reservations that belong to your organization. Prefer a scannable list? See the API Reference.

Check Availability

Auth: API key
POST/api/v1/delivery/availability

Check whether an address is inside the delivery area and which delivery windows are currently open for it. Provide the full street address whenever you have it — street, city, state, and ZIP together resolve against precise polygon coverage, while a ZIP alone falls back to coarser ZIP-level coverage. Optional if you reserve by time — but recommended for showing customers accurate windows and order-by deadlines.

addressobjectRequired
The delivery address to check. The same fields are also accepted flat at the top level of the body.
address.streetstringRecommended
Street address, including the house number.
address.citystringRecommended
City name.
address.statestringRecommended
Two-letter state code.
address.zipstringRequired
5-digit ZIP code. Send the full address as well — ZIP-only checks use coarser coverage.

Testing tip

A GET variant is available for quick testing: GET /api/v1/delivery/availability?street=&city=&state=&zip=. Use the POST form in production.
Request
curl -X POST "https://api.filld.dev/api/v1/delivery/availability" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "address": {
      "street": "12 Main St",
      "city": "Monsey",
      "state": "NY",
      "zip": "10952"
    }
  }'
Response — 200 OK
{
  "covered": true,
  "zone": { "id": "zone_mnsy01", "name": "Monsey" },
  "slots": [
    {
      "slotId": "slot_UGsxNDQzfDIwMjYtMDctMDc",
      "date": "2026-07-07",
      "dayOfWeek": 2,
      "window": { "start": "09:00", "end": "12:00" },
      "label": "Tue, Jul 7 · 9:00 AM – 12:00 PM",
      "orderBy": "2026-07-06T19:00:00.000Z",
      "availability": "available"
    },
    {
      "slotId": "slot_UGsxNDQzfDIwMjYtMDctMDg",
      "date": "2026-07-08",
      "dayOfWeek": 3,
      "window": { "start": "14:00", "end": "17:00" },
      "label": "Wed, Jul 8 · 2:00 PM – 5:00 PM",
      "orderBy": "2026-07-08T04:00:00.000Z",
      "availability": "limited"
    }
  ]
}

When the address is outside the delivery area, the response is covered: false with zone: null and an empty slots array.

  • slotId is an opaque token. Pass it back verbatim when reserving; do not parse it or construct your own.
  • availability is "available" or "limited" (only a few spots left).
  • orderBy is the instant after which the slot can no longer be reserved.

Response statuses

  • 200Availability returned.
  • 400invalid_request — the address is missing or malformed.
  • 401unauthorized — missing or invalid API key.
  • 429rate_limited — too many requests.

Reserve a Slot

Auth: API key
POST/api/v1/delivery/reservations

Books a delivery slot. By default the reservation comes back confirmed — the slot is booked and nothing else is required. Provide slotId (from /availability) or time— the customer's requested delivery time. Pass ttlMinutes for an opt-in checkout-start hold instead.

slotIdstringConditional
The slot token returned by /availability, passed back verbatim. Provide slotId or time.
timestringConditional
ISO 8601 date-time, Eastern (offset-less = Eastern wall time) — the customer's requested delivery time. The reservation is booked into whichever offered window covers it. Provide slotId or time.
addressobjectRequired
The delivery address for the order.
posOrderRefstringOptional
Your POS order number, attached at creation — no confirm call needed.
customerRefstringOptional
Your identifier for the customer. Opaque to Evergreen; echoed back on the reservation.
partnerOrderRefstringOptional
Your order or cart identifier.
ttlMinutesnumberOptional
Opt-in hold mode: creates the reservation as "held" with an expiry, from 5 to 120 minutes; confirm it before it lapses. Omit for the default — an immediately confirmed booking.
Request
curl -X POST "https://api.filld.dev/api/v1/delivery/reservations" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "slotId": "slot_UGsxNDQzfDIwMjYtMDctMDc",
    "address": {
      "street": "12 Main St",
      "city": "Monsey",
      "state": "NY",
      "zip": "10952"
    },
    "customerRef": "cust_123"
  }'
Response — 201 Created
{
  "reservationId": "res_9f2c7a1e4b8d",
  "status": "confirmed",
  "slot": {
    "slotId": "slot_UGsxNDQzfDIwMjYtMDctMDc",
    "date": "2026-07-07",
    "window": { "start": "09:00", "end": "12:00" },
    "label": "Tue, Jul 7 · 9:00 AM – 12:00 PM"
  },
  "zone": { "id": "zone_mnsy01", "name": "Monsey" },
  "expiresAt": null,
  "customerRef": "cust_123",
  "partnerOrderRef": null,
  "posOrderRef": null,
  "createdAt": "2026-07-03T14:15:00.000Z",
  "confirmedAt": "2026-07-03T14:15:00.000Z",
  "cancelledAt": null
}

This reservation object is the shape returned by every reservation endpoint. expiresAt is null for the default confirmed booking; in opt-in hold mode it is the instant the hold lapses if it is not confirmed. When reserving by time, slot tells you the delivery window the time landed in — display that window to the customer.

Response statuses

  • 201Slot booked (or hold created, when ttlMinutes is passed).
  • 400invalid_slot_id — the slot token is malformed. invalid_request — the body is malformed, or neither slotId nor a parseable time was provided.
  • 409slot_unavailable — the window is full or no longer offered, or no delivery window covers the requested time; re-fetch availability. order_by_passed— the window's orderBy deadline has passed.
  • 422address_not_covered — the address is outside the delivery area. zone_mismatch — the slot does not serve that address.
  • 401unauthorized — missing or invalid API key.
  • 429rate_limited — too many requests.

List Reservations

Auth: API key
GET/api/v1/delivery/reservations

List your organization's reservations, most recent first. Returns up to 100 reservations.

statusstringOptional
Filter by status: one of held, confirmed, cancelled, expired.
datestringOptional
Filter by delivery date, YYYY-MM-DD (store-local).
Request
curl "https://api.filld.dev/api/v1/delivery/reservations?status=confirmed&date=2026-07-07" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX"
Response — 200 OK
{
  "reservations": [
    {
      "reservationId": "res_9f2c7a1e4b8d",
      "status": "confirmed",
      "slot": {
        "slotId": "slot_UGsxNDQzfDIwMjYtMDctMDc",
        "date": "2026-07-07",
        "window": { "start": "09:00", "end": "12:00" },
        "label": "Tue, Jul 7 · 9:00 AM – 12:00 PM"
      },
      "zone": { "id": "zone_mnsy01", "name": "Monsey" },
      "expiresAt": "2026-07-03T14:45:00.000Z",
      "customerRef": "cust_123",
      "partnerOrderRef": "cart_88213",
      "posOrderRef": "SO-448291",
      "createdAt": "2026-07-03T14:15:00.000Z",
      "confirmedAt": "2026-07-03T14:22:31.000Z",
      "cancelledAt": null
    }
  ]
}

Response statuses

  • 200Reservations returned.
  • 401unauthorized — missing or invalid API key.
  • 429rate_limited — too many requests.

Get a Reservation

Auth: API key
GET/api/v1/delivery/reservations/{id}

Fetch a single reservation by its reservationId. A reservation that belongs to another organization returns 404, the same as one that does not exist.

idstringRequired
The reservationId returned when the reservation was created.
Request
curl "https://api.filld.dev/api/v1/delivery/reservations/res_9f2c7a1e4b8d" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX"
Response — 200 OK
{
  "reservationId": "res_9f2c7a1e4b8d",
  "status": "confirmed",
  "slot": {
    "slotId": "slot_UGsxNDQzfDIwMjYtMDctMDc",
    "date": "2026-07-07",
    "window": { "start": "09:00", "end": "12:00" },
    "label": "Tue, Jul 7 · 9:00 AM – 12:00 PM"
  },
  "zone": { "id": "zone_mnsy01", "name": "Monsey" },
  "expiresAt": null,
  "customerRef": "cust_123",
  "partnerOrderRef": null,
  "posOrderRef": null,
  "createdAt": "2026-07-03T14:15:00.000Z",
  "confirmedAt": "2026-07-03T14:15:00.000Z",
  "cancelledAt": null
}

Response statuses

  • 200Reservation returned.
  • 404not_found — no such reservation in your organization.
  • 401unauthorized — missing or invalid API key.

Confirm a Reservation

Auth: API key
POST/api/v1/delivery/reservations/{id}/confirm

Attach your POS order number to a reservation (optional). Include posOrderRef so the store can reconcile the reservation against your order. The call is required only to keep an opt-in hold alive — confirming a held reservation before expiresAt turns it into a booking. Idempotent: confirming an already-confirmed reservation updates the references and returns 200.

posOrderRefstringOptional
Your order number for the placed order. Strongly recommended.
partnerOrderRefstringOptional
Your order or cart identifier.
customerRefstringOptional
Your identifier for the customer.
Request
curl -X POST "https://api.filld.dev/api/v1/delivery/reservations/res_9f2c7a1e4b8d/confirm" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "posOrderRef": "SO-448291",
    "partnerOrderRef": "cart_88213"
  }'
Response — 200 OK
{
  "reservationId": "res_9f2c7a1e4b8d",
  "status": "confirmed",
  "slot": {
    "slotId": "slot_UGsxNDQzfDIwMjYtMDctMDc",
    "date": "2026-07-07",
    "window": { "start": "09:00", "end": "12:00" },
    "label": "Tue, Jul 7 · 9:00 AM – 12:00 PM"
  },
  "zone": { "id": "zone_mnsy01", "name": "Monsey" },
  "expiresAt": "2026-07-03T14:45:00.000Z",
  "customerRef": "cust_123",
  "partnerOrderRef": "cart_88213",
  "posOrderRef": "SO-448291",
  "createdAt": "2026-07-03T14:15:00.000Z",
  "confirmedAt": "2026-07-03T14:22:31.000Z",
  "cancelledAt": null
}

Response statuses

  • 200References updated (and, in hold mode, the hold becomes a booking).
  • 409reservation_expired — (hold mode) the hold lapsed before confirmation; reserve a new slot. reservation_cancelled — the reservation was cancelled and cannot be confirmed.
  • 404not_found — no such reservation in your organization.
  • 401unauthorized — missing or invalid API key.

Cancel a Reservation

Auth: API key
DELETE/api/v1/delivery/reservations/{id}

Cancel a hold or a confirmed reservation and release its capacity — for example, when the customer cancels the order or switches to a different window. Cancelling an already-cancelled or expired reservation is a no-op that returns the current state.

idstringRequired
The reservationId to cancel.
Request
curl -X DELETE "https://api.filld.dev/api/v1/delivery/reservations/res_9f2c7a1e4b8d" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX"
Response — 200 OK
{
  "reservationId": "res_9f2c7a1e4b8d",
  "status": "cancelled",
  "slot": {
    "slotId": "slot_UGsxNDQzfDIwMjYtMDctMDc",
    "date": "2026-07-07",
    "window": { "start": "09:00", "end": "12:00" },
    "label": "Tue, Jul 7 · 9:00 AM – 12:00 PM"
  },
  "zone": { "id": "zone_mnsy01", "name": "Monsey" },
  "expiresAt": "2026-07-03T14:45:00.000Z",
  "customerRef": "cust_123",
  "partnerOrderRef": "cart_88213",
  "posOrderRef": null,
  "createdAt": "2026-07-03T14:15:00.000Z",
  "confirmedAt": null,
  "cancelledAt": "2026-07-03T14:31:02.000Z"
}

Response statuses

  • 200Reservation cancelled (or already inactive).
  • 404not_found — no such reservation in your organization.
  • 401unauthorized — missing or invalid API key.

Send an Order

Auth: API key
POST/api/v1/orders

Create an order. Evergreen's own shoppers pick it in the store; when picking is finished it is checked out at the register on your account. Returns 201 Created with an empty body and a Location header carrying the order number.

X-Customer-PinstringRequired
The PIN of your on-account customer (customerId). It authorizes the on-account charge when the picked order is checked out. Evergreen keeps it encrypted until then and deletes it right after.
customerIdstring (≤8 chars) · bodyRequired
Your on-account customer id. Every order is billed on account to it (payment method OnAccount).
customerobject · bodyOptional
Not used for billing. firstName / lastName / phone are used for the recipient only when deliveryAddress.name / phoneNumber are missing.
externalOrderIdstring (≤20 chars) · bodyOptional
Your own order reference; must be unique per order. Used by GET /orders/external/{externalOrderId}. If you send the same externalOrderId twice, you get 409 duplicate_order and no second order is created.
itemsarray · bodyRequired
Order lines. Must be non-empty, at most 200.
items[].productCodestring (≤12 chars) · bodyRequired
The item's barcode or item code (PLU). It must be an item the fulfilling store carries. Otherwise the whole order is rejected with 422 unknown_items, which names the codes.
items[].quantitynumber · bodyRequired
A count of units. For a by-weight line (unitOfMeasure "Lbs"), the weight in pounds.
items[].unitOfMeasurestring · bodyOptional
"Lbs" for a by-weight line; anything else ("Unit", "Case") is a count.
items[].descriptionstring (≤30 chars) · bodyOptional
Line description. Kept for reference only; the store uses its own item names.
items[].unitPrice / totalPrice / priceQtynumber · bodyOptional
Accepted so existing payloads keep working, and stored for audit. They are NOT used for billing: Evergreen prices every line at the store's regular shelf price (see notes).
items[].notestring · bodyOptional
Line note, visible to the shopper.
deliveryAddressobject · bodyDelivery
The recipient of the order.
deliveryAddress.namestring · bodyOptional
Recipient name. It is printed on the order and the delivery label.
deliveryAddress.phoneNumberstring · bodyOptional
Recipient phone, for the driver. Evergreen does not text or email the recipient.
deliveryAddress.addressobject · bodyDelivery
addressLine1 (≤30 chars), addressLine2, city, state, zipCode. It must be inside our delivery area; otherwise you get 422 address_not_covered.
orderMethodstring · bodyOptional
"Pickup" or "Delivery". Defaults to Delivery when deliveryAddress is present.
pickupDeliveryTimestring · bodyConditional
ISO 8601 date-time, Eastern time. This is the requested delivery date and time; the date cannot be in the past. The order goes into the delivery window that covers this time. If no window covers it, it goes into the next window later that same day. If there is none, it is accepted as requested and you get a warning. Window capacity is not checked. Required for Delivery orders without a reservationId.
deliveryWindowobject · bodyOptional
Evergreen extension: { "start": "HH:MM", "end": "HH:MM" } (store time). Use it to name the window yourself. It is accepted as sent; the date still comes from pickupDeliveryTime.
notestring · bodyOptional
Order-level note, shown to the store.
payment / paymentEndpointobject · bodyOptional
Ignored. Orders are always billed OnAccount to customerId with the X-Customer-Pin you send. No payment webhook is called.
priorityinteger · bodyOptional
Evergreen extension: 1 | 2 | 3 (1 = highest; omitted = normal). Higher-priority orders are picked first. Other values return 400 invalid_request.
reservationIdstring · bodyOptional
Evergreen extension, optional: attach a slot you reserved earlier (res_…). The order takes that reservation's window, and the reservation is confirmed. You do not need a reservation to send an order.
storestring · bodyOptional
Evergreen extension, pickup orders only: the fulfilling store, e.g. "uptown". Delivery orders are routed by address.
Request
curl -X POST "https://api.filld.dev/api/v1/orders" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX" \
  -H "X-Customer-Pin: 1234" \
  -H "Content-Type: application/json" \
  -d '{
    "customerId": "18452",
    "externalOrderId": "cart_88213",
    "orderMethod": "Delivery",
    "pickupDeliveryTime": "2026-07-07T10:00:00",
    "items": [
      {
        "productCode": "412009",
        "description": "Golden Flow OJ 64oz",
        "quantity": 2,
        "unitOfMeasure": "Unit"
      },
      {
        "productCode": "286748",
        "description": "Chicken Cutlets",
        "quantity": 3.5,
        "unitOfMeasure": "Lbs",
        "note": "Sliced thin, please"
      }
    ],
    "deliveryAddress": {
      "name": "Chaim Brachfeld",
      "phoneNumber": "8455550142",
      "address": {
        "addressLine1": "12 Main St",
        "city": "Monsey",
        "state": "NY",
        "zipCode": "10952"
      }
    },
    "priority": 2,
    "note": "Leave by the side door"
  }'
Response — 201 Created (empty body)
HTTP/1.1 201 Created
Location: /orders/id/SCN1254
x-evergreen-delivery-time: 2026-07-07T12:00:00-04:00
x-evergreen-store: monsey
x-evergreen-window: 2026-07-07 09:00-12:00
  • Contract-compatible with the POSwithLogic API: set your integration's base URL to https://api.filld.dev/api/v1 and use your Evergreen x-api-key. The request body, the 201 + Location response and the error format (RFC 7807 problem+json) are the same as the POS API's.
  • What happens to the order: it goes into Evergreen's picking queue, not straight to the POS. Our shoppers pick it in the store. When picking is finished, it is entered in the POS as picked, checked out on account to your customerId (OnAccount, authorized with your X-Customer-Pin), labeled and delivered. Follow each step in the order's status (see List & Track Orders).
  • The Location header carries your order number, your Evergreen reference (e.g. SCN1254). It is the number the store uses and it never changes. The order has a POS order id (posOrderId) only after it is checked out.
  • Pricing: every line is billed at the fulfilling store's REGULAR shelf price. Sale prices, multi-buy ("2 for") and case prices are never applied, and nothing is added on top. Prices you send are ignored (kept for audit). By-weight lines are billed by the weight actually picked. The receipt shows what the register actually charged.
  • Account fees: if Evergreen has set up fees or standard items for your account (for example a handling fee or bags), they are added to every order automatically. Item lines are picked with the order; fee lines are charged at checkout. Both appear on the POS order and on the receipt.
  • Substitutions (SCN orders): if an item is out of stock, the shopper may substitute a similar item at the same price or cheaper (at most 5% more). The recipient is not contacted. Substitutes and items not found are listed on the receipt.
  • Slots are not booked: the requested date and time are accepted without a capacity check. We only check that the address is in our delivery area (422 address_not_covered), that the date is not in the past (422 invalid_delivery_date) and that the time is valid (400). A reservation (reservationId) is optional; reservations still work if you use them.
  • If no delivery window covers the requested time on that date, the order is still accepted (201). You also get an x-evergreen-warning header and a JSON body (warning "no_matching_window"); the store will confirm the time.
  • Optional Evergreen extensions: deliveryWindow — name the window yourself; reservationId — use a slot you reserved earlier; store — pickup orders only; priority — 1 | 2 | 3 (1 = highest). A standard payload works without them.
  • Unknown items: if any productCode is not an item the fulfilling store carries, the whole order is rejected with 422 unknown_items, which lists the codes. Nothing is created; fix the codes and send the order again.
  • Hold for review (set by Evergreen per partner): the order is accepted the same way but stays at status accepted until the store releases it into picking. You can edit it until then.
  • Sandbox: orders created with a test key are not placed or picked. You receive a TEST-prefixed order number (Location: /orders/id/TEST-48210937, plus x-evergreen-sandbox: true). Validation is lighter than live.
  • Sandbox failure simulation: include the string simulate=pos_error anywhere in note to receive a 400 in the standard problem+json format.

Response statuses

  • 201Order created — empty body; the Location header carries the order number.
  • 400invalid_request — The body is malformed: no items, a line without productCode or a positive quantity, a missing customerId, a delivery order without a valid pickupDeliveryTime, or a bad deliveryWindow / priority.
  • 409duplicate_order — An order with this externalOrderId was already received. The original stands; no second order was created.
  • 409reservation_expired / reservation_cancelled — The reservationId you sent no longer holds a slot. Send the order without it, or reserve again.
  • 422address_not_covered — The delivery address is outside our delivery area.
  • 422invalid_delivery_date — The requested date is in the past.
  • 422unknown_items — One or more productCodes are not sold at the fulfilling store (the codes are listed). Nothing was created.
  • 401unauthorized — Missing or invalid API key.
  • 429rate_limited — Too many requests.
  • OtherAny other error uses the same problem+json format ({ type, title, status, detail, code }).

Edit an Order

Auth: API key
PATCH/api/v1/orders/id/{orderNumber}

Edit an order while its tracking status is still accepted (held for review, not yet released to picking). All body fields are optional; send at least one. Returns the updated order.

orderNumberstring · pathRequired
The order number to edit.
itemsarray · bodyOptional
Full replacement for the order's lines — same line shape as create. Must be non-empty when present.
pickupDeliveryTimestring · bodyOptional
ISO 8601 date-time, Eastern — moves the order to another date/window. Same rules as create (address in area, date not past; no capacity check).
deliveryWindowobject · bodyOptional
{ "start": "HH:MM", "end": "HH:MM" } — name the window yourself, as on create.
deliveryAddressobject · bodyOptional
Merged into the order's address (partial updates are fine); the window is worked out again for the new address.
notestring · bodyOptional
Replaces the order-level note.
priorityinteger · bodyOptional
1 | 2 | 3 (1 = highest, omitted = normal). Evergreen extension — the store can use it to sequence work. Other values return 400 invalid_request.
Request
curl -X PATCH "https://api.filld.dev/api/v1/orders/id/SCN1043" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "pickupDeliveryTime": "2026-07-07T14:00:00",
    "note": "Customer added items",
    "items": [
      { "productCode": "412009", "quantity": 3 },
      { "productCode": "573301", "quantity": 1 }
    ]
  }'
Response — 200 OK (the updated order)
{
  "id": "SCN1043",
  "externalOrderId": "cart_88213",
  "status": "Picked",
  "orderMethod": "Delivery",
  "pickupDeliveryTime": "2026-07-07T12:00:00-04:00",
  "items": [
    { "productCode": "041303001233", "description": "Whole Milk 1 Gal", "quantity": 2, "unitOfMeasure": "Unit", "unitPrice": 4.99, "totalPrice": 9.98, "pickStatus": "picked" },
    { "productCode": "4011", "description": "Bananas", "quantity": 2, "unitOfMeasure": "Lbs", "unitPrice": 0.79, "totalPrice": 1.58, "pickStatus": "picked" },
    { "productCode": "286748", "description": "Tahini 16 oz", "quantity": 1, "unitOfMeasure": "Unit", "unitPrice": 6.49, "totalPrice": 6.49, "pickStatus": "not_found" }
  ],
  "deliveryAddress": {
    "name": "Chana Cohen",
    "phoneNumber": "8455551234",
    "address": { "addressLine1": "12 Maple Ave", "city": "Monsey", "state": "NY", "zipCode": "10952" }
  },
  "tracking": {
    "status": "picking_finished",
    "scnNumber": "SCN1043",
    "posOrderId": null,
    "invoiceNumber": null,
    "store": "monsey",
    "window": { "date": "2026-07-07", "start": "09:00", "end": "12:00" },
    "eta": null,
    "driver": null,
    "trackUrl": null,
    "receiptUrl": null,
    "deliveredAt": null,
    "photoUrl": null,
    "photo2Url": null,
    "signatureUrl": null,
    "proofUrl": null,
    "receiptReady": true,
    "timeline": [
      { "status": "received", "at": "2026-07-06T18:02:11.000Z" },
      { "status": "picking_started", "at": "2026-07-07T08:10:44.000Z" },
      { "status": "picking_finished", "at": "2026-07-07T08:31:02.000Z" }
    ]
  },
  "receipt": {
    "orderNumber": "SCN1043",
    "scnNumber": "SCN1043",
    "externalOrderId": "cart_88213",
    "posOrderId": "1630X",
    "posInvoiceNumber": "611234567",
    "posStatus": "Done",
    "store": { "slug": "monsey", "name": "Evergreen Monsey" },
    "delivery": { "method": "Delivery", "date": "2026-07-07", "window": { "start": "09:00", "end": "12:00" } },
    "recipient": { "name": "Chana Cohen", "phone": "+18455551234", "address": "12 Maple Ave, Monsey, NY 10952" },
    "lines": [
      { "productCode": "041303001233", "description": "Whole Milk 1 Gal", "quantity": 2, "unitOfMeasure": "Unit", "unitPrice": 4.99, "lineTotal": 9.98, "ordered": { "quantity": 2, "weightLb": null, "description": "Whole Milk 1 Gal" } },
      { "productCode": "4011", "description": "Bananas", "quantity": 1.84, "unitOfMeasure": "Lbs", "unitPrice": 0.79, "lineTotal": 1.45, "ordered": { "quantity": 1, "weightLb": 2, "description": "Bananas" } }
    ],
    "notCharged": [
      { "productCode": "286748", "description": "Tahini 16 oz", "quantity": 1 }
    ],
    "subtotal": 11.43,
    "fees": [
      { "label": "Handling fee", "productCode": "301", "amount": 2.5 }
    ],
    "total": 13.93,
    "currency": "USD",
    "pdfUrl": "https://api.filld.dev/api/v1/orders/id/SCN1043/receipt",
    "generatedAt": "2026-07-07T08:35:00.000Z"
  }
}
  • Editable only while status is accepted, which happens only when your organization's orders are held for review. Orders that go straight into picking (status received) cannot be edited and return 409 order_not_editable: "This order was already sent to the store and can no longer be edited."
  • Items are priced again at the regular shelf price, and unknown codes are rejected (422 unknown_items), as on create.
  • The response is the updated order — same shape as GET /orders/id/{orderNumber}; check pickupDeliveryTime and tracking on it.
  • Sandbox: orders created with a test key are treated as sent immediately, so sandbox edits return order_not_editable — editing is live-only.

Response statuses

  • 200Order updated.
  • 400invalid_request — A bad items array, an unparseable pickupDeliveryTime, or a priority outside 1–3.
  • 409order_not_editable — The order was already sent to the store and can no longer be edited.
  • 404not_found — The order was not created through this API, or does not belong to your organization.
  • 401unauthorized — Missing or invalid API key.

List & Track Orders

Auth: API key
GET/api/v1/orders

Tracking for all your orders: the newest 200, each with its status, window, ETA, driver, delivery proof and full timeline. To follow specific orders, use Batch Tracking.

statusstring · queryOptional
Filter by lifecycle status: accepted, received, picking_started, picking_finished, sent_to_pos, checked_out, label_created, out_for_delivery, delivered, or cancelled.
datestring · queryOptional
Filter by delivery date, YYYY-MM-DD.
sincestring · queryOptional
ISO 8601 instant — return only orders whose tracking changed after it. Pass your last poll time for cheap incremental updates.
Request
curl "https://api.filld.dev/api/v1/orders?since=2026-07-07T13:00:00Z" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX"
Response — 200 OK
{
  "orders": [
    {
      "orderNumber": "SCN1043",
      "scnNumber": "SCN1043",
      "posOrderId": "448291",
      "invoiceNumber": "774612",
      "externalOrderId": "cart_88213",
      "orderMethod": "Delivery",
      "status": "out_for_delivery",
      "window": { "date": "2026-07-07", "start": "09:00", "end": "12:00" },
      "scheduledTime": "2026-07-07T12:00:00-04:00",
      "priority": 1,
      "itemCount": 12,
      "eta": "2026-07-07T14:42:00.000Z",
      "driver": "Moshe",
      "trackUrl": "https://filld.link/t/8f2ac91d",
      "deliveredAt": null,
      "photoUrl": null,
      "photo2Url": null,
      "signatureUrl": null,
      "proofUrl": null,
      "receiptUrl": null,
      "receiptReady": true,
      "timeline": [
        { "status": "received", "at": "2026-07-06T18:02:11.000Z" },
        { "status": "picking_started", "at": "2026-07-07T08:10:44.000Z" },
        { "status": "picking_finished", "at": "2026-07-07T08:31:02.000Z" },
        { "status": "sent_to_pos", "at": "2026-07-07T08:31:05.000Z" },
        { "status": "checked_out", "at": "2026-07-07T12:20:03.000Z" },
        { "status": "label_created", "at": "2026-07-07T12:41:27.000Z" },
        { "status": "out_for_delivery", "at": "2026-07-07T13:05:12.000Z" }
      ],
      "editedAt": null,
      "createdAt": "2026-07-06T18:02:11.000Z",
      "updatedAt": "2026-07-07T13:05:12.000Z"
    }
  ]
}
  • Statuses, in order: accepted (held for review, only if your orders are held) → received (in our picking queue) → picking_started → picking_finished (picked and packed) → sent_to_pos (entered in the POS as picked) → checked_out (charged on your account at the register; the receipt is ready) → label_created → out_for_delivery → delivered. cancelled can happen at any point before delivery.
  • timeline lists every step the order reached, each with its time. eta, driver and trackUrl appear once the order is out for delivery. When it is delivered you also get photoUrl, photo2Url, signatureUrl, proofUrl (the proof-of-delivery page) and receiptUrl (the signed delivery receipt), when the driver captured them.
  • receiptReady turns true once the order is checked out at the register. From then on, the order detail (GET /orders/id/{orderNumber}) has a receipt object — what the POS actually charged — and the printable receipt is at its pdfUrl.
  • How fresh: picking steps show right away. The POS checkout (checked_out) and the delivery steps are checked every few minutes, so expect a delay of up to about 5 minutes.
  • Reference ids: orderNumber (= scnNumber, e.g. "SCN1043") is your Evergreen order number and never changes. posOrderId is the POS order id, present once the order is in the POS. invoiceNumber is present once the order is checked out.
  • slotOverride is set when the order was accepted outside a normal delivery window ("unscheduled" | "deadline"). priority (1 | 2 | 3, 1 = highest) is present only when it was set.
  • Sandbox: tracking works with a test key but stays at sent_to_pos, because sandbox orders are not picked.

Response statuses

  • 200Orders returned (newest 200).
  • 401unauthorized — Missing or invalid API key.
  • 429rate_limited — Too many requests.

Batch Tracking

Auth: API key
POST/api/v1/orders/batch

Batch order tracking by id. Send up to 200 ids — matched against the order number, the SCN number, or your externalOrderId, mixed freely — and get back exactly those orders, in the same row shape as GET /api/v1/orders.

orderIdsarray of strings · bodyRequired
Up to 200 ids, matched against the order number, the SCN number, or your externalOrderId — mix freely.
Request
curl -X POST "https://api.filld.dev/api/v1/orders/batch" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX" \
  -H "Content-Type: application/json" \
  -d '{
    "orderIds": ["SCN1043", "cart_88213", "cart_88240"]
  }'
Response — 200 OK
{
  "orders": [
    {
      "orderNumber": "SCN1043",
      "scnNumber": "SCN1043",
      "posOrderId": "448291",
      "invoiceNumber": "774612",
      "externalOrderId": "cart_88213",
      "orderMethod": "Delivery",
      "status": "delivered",
      "window": { "date": "2026-07-07", "start": "09:00", "end": "12:00" },
      "scheduledTime": "2026-07-07T12:00:00-04:00",
      "itemCount": 12,
      "eta": "2026-07-07T14:42:00.000Z",
      "driver": "Moshe",
      "trackUrl": "https://filld.link/t/8f2ac91d",
      "deliveredAt": "2026-07-07T14:39:51.000Z",
      "photoUrl": "https://pod.example.com/p/8f2ac91d-1.jpg",
      "photo2Url": null,
      "signatureUrl": "https://pod.example.com/s/8f2ac91d.png",
      "proofUrl": "https://filld.link/t/8f2ac91d",
      "receiptUrl": "https://pod.example.com/r/8f2ac91d.pdf",
      "receiptReady": true,
      "timeline": [
        { "status": "received", "at": "2026-07-06T18:02:11.000Z" },
        { "status": "picking_started", "at": "2026-07-07T08:10:44.000Z" },
        { "status": "picking_finished", "at": "2026-07-07T08:31:02.000Z" },
        { "status": "sent_to_pos", "at": "2026-07-07T08:31:05.000Z" },
        { "status": "checked_out", "at": "2026-07-07T12:20:03.000Z" },
        { "status": "label_created", "at": "2026-07-07T12:41:27.000Z" },
        { "status": "out_for_delivery", "at": "2026-07-07T13:05:12.000Z" },
        { "status": "delivered", "at": "2026-07-07T14:39:51.000Z" }
      ],
      "editedAt": null,
      "createdAt": "2026-07-06T18:02:11.000Z",
      "updatedAt": "2026-07-07T14:41:00.000Z"
    },
    {
      "orderNumber": "SCN1044",
      "scnNumber": "SCN1044",
      "posOrderId": null,
      "invoiceNumber": null,
      "externalOrderId": "cart_88240",
      "orderMethod": "Delivery",
      "status": "received",
      "window": { "date": "2026-07-08", "start": "14:00", "end": "17:00" },
      "scheduledTime": "2026-07-08T17:00:00-04:00",
      "itemCount": 4,
      "eta": null,
      "driver": null,
      "trackUrl": null,
      "deliveredAt": null,
      "photoUrl": null,
      "photo2Url": null,
      "signatureUrl": null,
      "proofUrl": null,
      "receiptUrl": null,
      "receiptReady": false,
      "timeline": [
        { "status": "received", "at": "2026-07-07T15:12:40.000Z" }
      ],
      "editedAt": null,
      "createdAt": "2026-07-07T15:12:40.000Z",
      "updatedAt": "2026-07-07T15:12:40.000Z"
    }
  ]
}
  • This is the recommended way to poll. Send the ids of your open orders (up to 200 per call) every few minutes, and drop an order from your list once it is delivered or cancelled. Statuses refresh every few minutes, so polling more often than once a minute gains nothing.
  • Ids that don't match anything are left out of the response; that is not an error. An order matched by two of its ids is returned once. In the example, "SCN1043" and "cart_88213" are the same order, so three ids return two rows.

Response statuses

  • 200Matching orders returned; ids that match nothing are simply absent.
  • 400invalid_request — orderIds missing, empty, containing non-strings, or more than 200 ids.
  • 401unauthorized — Missing or invalid API key.
  • 429rate_limited — Too many requests.

Get Order Status

Auth: API key
GET/api/v1/orders/id/{orderNumber}

Fetch an order by its order number: its lines, the tracking block and, once it is checked out, the receipt.

orderNumberstring · pathRequired
The order number from the create response's Location header.
Request
curl "https://api.filld.dev/api/v1/orders/id/SCN1043" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX"
Response — 200 OK
{
  "id": "SCN1043",
  "externalOrderId": "cart_88213",
  "status": "Picked",
  "orderMethod": "Delivery",
  "pickupDeliveryTime": "2026-07-07T12:00:00-04:00",
  "items": [
    { "productCode": "041303001233", "description": "Whole Milk 1 Gal", "quantity": 2, "unitOfMeasure": "Unit", "unitPrice": 4.99, "totalPrice": 9.98, "pickStatus": "picked" },
    { "productCode": "4011", "description": "Bananas", "quantity": 2, "unitOfMeasure": "Lbs", "unitPrice": 0.79, "totalPrice": 1.58, "pickStatus": "picked" },
    { "productCode": "286748", "description": "Tahini 16 oz", "quantity": 1, "unitOfMeasure": "Unit", "unitPrice": 6.49, "totalPrice": 6.49, "pickStatus": "not_found" }
  ],
  "deliveryAddress": {
    "name": "Chana Cohen",
    "phoneNumber": "8455551234",
    "address": { "addressLine1": "12 Maple Ave", "city": "Monsey", "state": "NY", "zipCode": "10952" }
  },
  "tracking": {
    "status": "picking_finished",
    "scnNumber": "SCN1043",
    "posOrderId": null,
    "invoiceNumber": null,
    "store": "monsey",
    "window": { "date": "2026-07-07", "start": "09:00", "end": "12:00" },
    "eta": null,
    "driver": null,
    "trackUrl": null,
    "receiptUrl": null,
    "deliveredAt": null,
    "photoUrl": null,
    "photo2Url": null,
    "signatureUrl": null,
    "proofUrl": null,
    "receiptReady": true,
    "timeline": [
      { "status": "received", "at": "2026-07-06T18:02:11.000Z" },
      { "status": "picking_started", "at": "2026-07-07T08:10:44.000Z" },
      { "status": "picking_finished", "at": "2026-07-07T08:31:02.000Z" }
    ]
  },
  "receipt": {
    "orderNumber": "SCN1043",
    "scnNumber": "SCN1043",
    "externalOrderId": "cart_88213",
    "posOrderId": "1630X",
    "posInvoiceNumber": "611234567",
    "posStatus": "Done",
    "store": { "slug": "monsey", "name": "Evergreen Monsey" },
    "delivery": { "method": "Delivery", "date": "2026-07-07", "window": { "start": "09:00", "end": "12:00" } },
    "recipient": { "name": "Chana Cohen", "phone": "+18455551234", "address": "12 Maple Ave, Monsey, NY 10952" },
    "lines": [
      { "productCode": "041303001233", "description": "Whole Milk 1 Gal", "quantity": 2, "unitOfMeasure": "Unit", "unitPrice": 4.99, "lineTotal": 9.98, "ordered": { "quantity": 2, "weightLb": null, "description": "Whole Milk 1 Gal" } },
      { "productCode": "4011", "description": "Bananas", "quantity": 1.84, "unitOfMeasure": "Lbs", "unitPrice": 0.79, "lineTotal": 1.45, "ordered": { "quantity": 1, "weightLb": 2, "description": "Bananas" } }
    ],
    "notCharged": [
      { "productCode": "286748", "description": "Tahini 16 oz", "quantity": 1 }
    ],
    "subtotal": 11.43,
    "fees": [
      { "label": "Handling fee", "productCode": "301", "amount": 2.5 }
    ],
    "total": 13.93,
    "currency": "USD",
    "pdfUrl": "https://api.filld.dev/api/v1/orders/id/SCN1043/receipt",
    "generatedAt": "2026-07-07T08:35:00.000Z"
  }
}
  • Only orders created through this API resolve.
  • status uses the POS names your integration already reads: OrderEntered (held), Unpicked (in the queue), InProgress (picking), Picked (packed), then the POS's own status (e.g. Done), or Cancelled. tracking.status gives the exact step (see List & Track Orders).
  • items are the lines as ordered, priced at the regular shelf price. pickStatus is pending, picked, partial or not_found.
  • The tracking object has the status, scnNumber, posOrderId, invoiceNumber, store, window, eta, driver, trackUrl, deliveredAt, photoUrl, photo2Url, signatureUrl, proofUrl, receiptUrl, receiptReady and the full timeline.
  • receipt (null until the order is checked out) is what the register ACTUALLY CHARGED, read back from the POS order: posInvoiceNumber, posStatus, and one line per POS line — productCode, description, quantity (pounds on a "Lbs" line), unitOfMeasure, unitPrice, lineTotal and, when it matches an ordered item, ordered { quantity, weightLb, description }. A substitute appears under its own code. notCharged lists ordered items the POS order doesn't charge for (not found). fees lists your account's fee lines as charged. Then subtotal, total and pdfUrl, the printable receipt (see Get a Receipt).
  • Sandbox: a TEST- id returns a stub order: { id, externalOrderId, status: "OrderEntered", pickupDeliveryTime, items: [], sandbox: true }. Test and live data are isolated — cross-mode lookups return 404.
  • Errors on this endpoint use the problem+json format.

Response statuses

  • 200The order as it currently stands.
  • 404not_found — The order was not created through this API, or does not belong to your organization.
  • 502pos_unreachable — Orders sent before Evergreen picking (read live from the POS) only: the order could not be retrieved right now. Safe to retry.
  • 401unauthorized — Missing or invalid API key.

Get a Receipt

Auth: API key
GET/api/v1/orders/id/{orderNumber}/receipt

The printable receipt: what the register actually charged (from the POS order), next to what was ordered, with items not charged and your account fees. Available once the order is checked out.

orderNumberstring · pathRequired
The order number (SCN…).
formatstring · queryOptional
"json" returns the receipt object (the same one as on the order detail) instead of the page.
Request
curl "https://api.filld.dev/api/v1/orders/id/SCN1043/receipt" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX"
Response — 200 OK (text/html — a print-ready page)
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
  • Returns a self-contained, print-friendly HTML page. To get a PDF, print it and choose Save as PDF, or render it with any HTML-to-PDF tool. Send your x-api-key header to fetch it; the receipt's pdfUrl points here.
  • Prices are what is billed: regular shelf prices, by-weight lines at the weight picked. The total matches what was checked out on your account.

Response statuses

  • 200The receipt page (or JSON with format=json).
  • 409receipt_not_ready — Picking isn't finished yet.
  • 404not_found — No such order for your organization, or an order sent before Evergreen picking (those have no receipt).
  • 401unauthorized — Missing or invalid API key.

Lookup by External Id

Auth: API key
GET/api/v1/orders/external/{externalOrderId}

Fetch an order by your own externalOrderId — the value you sent on the create call. Identical response shape to the id lookup.

externalOrderIdstring · pathRequired
Your order id, as sent in the create body's externalOrderId field.
Request
curl "https://api.filld.dev/api/v1/orders/external/cart_88213" \
  -H "x-api-key: evg_live_XXXXXXXXXXXXXXXX"
Response — 200 OK
{
  "id": "SCN1043",
  "externalOrderId": "cart_88213",
  "status": "Picked",
  "orderMethod": "Delivery",
  "pickupDeliveryTime": "2026-07-07T12:00:00-04:00",
  "items": [
    { "productCode": "041303001233", "description": "Whole Milk 1 Gal", "quantity": 2, "unitOfMeasure": "Unit", "unitPrice": 4.99, "totalPrice": 9.98, "pickStatus": "picked" },
    { "productCode": "4011", "description": "Bananas", "quantity": 2, "unitOfMeasure": "Lbs", "unitPrice": 0.79, "totalPrice": 1.58, "pickStatus": "picked" },
    { "productCode": "286748", "description": "Tahini 16 oz", "quantity": 1, "unitOfMeasure": "Unit", "unitPrice": 6.49, "totalPrice": 6.49, "pickStatus": "not_found" }
  ],
  "deliveryAddress": {
    "name": "Chana Cohen",
    "phoneNumber": "8455551234",
    "address": { "addressLine1": "12 Maple Ave", "city": "Monsey", "state": "NY", "zipCode": "10952" }
  },
  "tracking": {
    "status": "picking_finished",
    "scnNumber": "SCN1043",
    "posOrderId": null,
    "invoiceNumber": null,
    "store": "monsey",
    "window": { "date": "2026-07-07", "start": "09:00", "end": "12:00" },
    "eta": null,
    "driver": null,
    "trackUrl": null,
    "receiptUrl": null,
    "deliveredAt": null,
    "photoUrl": null,
    "photo2Url": null,
    "signatureUrl": null,
    "proofUrl": null,
    "receiptReady": true,
    "timeline": [
      { "status": "received", "at": "2026-07-06T18:02:11.000Z" },
      { "status": "picking_started", "at": "2026-07-07T08:10:44.000Z" },
      { "status": "picking_finished", "at": "2026-07-07T08:31:02.000Z" }
    ]
  },
  "receipt": {
    "orderNumber": "SCN1043",
    "scnNumber": "SCN1043",
    "externalOrderId": "cart_88213",
    "posOrderId": "1630X",
    "posInvoiceNumber": "611234567",
    "posStatus": "Done",
    "store": { "slug": "monsey", "name": "Evergreen Monsey" },
    "delivery": { "method": "Delivery", "date": "2026-07-07", "window": { "start": "09:00", "end": "12:00" } },
    "recipient": { "name": "Chana Cohen", "phone": "+18455551234", "address": "12 Maple Ave, Monsey, NY 10952" },
    "lines": [
      { "productCode": "041303001233", "description": "Whole Milk 1 Gal", "quantity": 2, "unitOfMeasure": "Unit", "unitPrice": 4.99, "lineTotal": 9.98, "ordered": { "quantity": 2, "weightLb": null, "description": "Whole Milk 1 Gal" } },
      { "productCode": "4011", "description": "Bananas", "quantity": 1.84, "unitOfMeasure": "Lbs", "unitPrice": 0.79, "lineTotal": 1.45, "ordered": { "quantity": 1, "weightLb": 2, "description": "Bananas" } }
    ],
    "notCharged": [
      { "productCode": "286748", "description": "Tahini 16 oz", "quantity": 1 }
    ],
    "subtotal": 11.43,
    "fees": [
      { "label": "Handling fee", "productCode": "301", "amount": 2.5 }
    ],
    "total": 13.93,
    "currency": "USD",
    "pdfUrl": "https://api.filld.dev/api/v1/orders/id/SCN1043/receipt",
    "generatedAt": "2026-07-07T08:35:00.000Z"
  }
}
  • Only orders created through this API resolve.
  • Same response as Get Order Status: the lines, the tracking object (status, timeline and delivery proof) and the receipt once it is checked out.
  • Errors on this endpoint use the problem+json format.

Response statuses

  • 200The order as it currently stands.
  • 404not_found — No order with that externalOrderId was created through this API by your organization.
  • 502pos_unreachable — The order could not be retrieved right now. Safe to retry.
  • 401unauthorized — Missing or invalid API key.

Error Handling

Errors come in two formats, matching each surface of the API:

  • Order endpoints (/orders…) return RFC 7807 problem+json — { type, title, status, detail, code } — where code is the machine-readable code.
  • Slot endpoints (/api/v1/delivery/…) return the { error, message } envelope.
Order endpoints — RFC 7807 problem+json
{
  "type": "https://httpproblems.com/http-status/409",
  "title": "Conflict",
  "status": 409,
  "detail": "This delivery window is no longer available. Fetch availability again for current options.",
  "code": "slot_unavailable"
}
Delivery endpoints — error envelope
{
  "error": "slot_unavailable",
  "message": "This delivery window is no longer available. Fetch availability again for current options."
}
HTTP statusError codesMeaning
200 / 201—Success.
400invalid_request, invalid_slot_idThe request body, query, or slot token is malformed.
401unauthorizedMissing or invalid x-api-key header.
404not_foundNo such reservation or order in your organization.
409slot_unavailable, order_by_passed, reservation_expired, reservation_cancelled, order_not_editable, duplicate_order, receipt_not_readyThe request conflicts with the current state of the slot, reservation, or order.
422address_not_covered, zone_mismatch, invalid_delivery_date, unknown_itemsThe address is outside the delivery area, the slot does not serve it, the date is in the past, or items aren't sold at the store.
429rate_limitedToo many requests. Back off and retry.
500internal_errorSomething went wrong on Evergreen's side. Safe to retry.
502pos_unreachableOrders sent before Evergreen picking only: the POS could not be reached. Safe to retry.

The codes above appear as code in problem+json on the order endpoints and as error in the envelope on the delivery endpoints.

Expect slot_unavailable under load

A 409 slot_unavailable at reserve time is normal when multiple platforms draw from the same capacity pool. Re-fetch availability and offer the customer the remaining windows.

Best Practices

  1. Poll in batches, every few minutes. Send your open order numbers to POST /orders/batch (up to 200 per call) and stop polling an order once it is delivered or cancelled.
  2. Send codes the store carries. An unknown productCode rejects the whole order (422 unknown_items); the error lists the codes to fix.
  3. If you reserve, reserve when the order is placed, not at slot display. Showing slots does not book them, and a reservation consumes real capacity immediately. Orders don't need a reservation.
  4. Attach your order number. After placing the order, call confirm with posOrderRef so the store can reconcile the reservation against the order.
  5. Release bookings you no longer need. DELETE the reservation if the order falls through or the customer switches windows. (In opt-in hold mode, unconfirmed holds expire on their own — confirm before expiresAt and keep one active hold per cart.)
  6. Handle slot_unavailable gracefully by re-fetching availability and presenting the remaining windows.
  7. Respect orderBy. Hide windows client-side once the deadline nears, rather than letting the reserve call fail.
  8. Send the full street address, not just a ZIP — polygon coverage is more precise than ZIP-level coverage.

Support

For integration questions, contact Filld to get API keys and a test key for development. Include your organization name so your keys can be provisioned against the right account.