Selling physical products

ListBee handles payment. You handle shipping. Use external fulfillment with a checkout schema to collect the buyer’s shipping address, then ship the order and update its status via the API.


How it works

  1. Create a listing with fulfillment: "external" and a checkout_schema that includes an address field.
  2. Buyer visits the product page, fills in their shipping address, and pays.
  3. ListBee fires an order.paid webhook with the buyer’s address in checkout_data.
  4. You ship the product and call POST /v1/orders/{id}/ship with tracking info.
  5. ListBee fires an order.shipped webhook.
  6. When the buyer receives the product, call POST /v1/orders/{id}/fulfill to mark it complete.

Walkthrough: selling shoes

Step 1: Create the listing

1import httpx
2
3resp = httpx.post(
4 "https://api.listbee.so/v1/listings",
5 headers={"Authorization": "Bearer lb_..."},
6 json={
7 "name": "Handmade Leather Boots",
8 "price": 18900,
9 "fulfillment": "external",
10 "checkout_schema": [
11 {
12 "key": "size",
13 "type": "select",
14 "label": "Shoe size",
15 "required": True,
16 "options": ["EU 38", "EU 39", "EU 40", "EU 41", "EU 42", "EU 43", "EU 44"],
17 },
18 {
19 "key": "shipping_address",
20 "type": "address",
21 "label": "Shipping address",
22 "required": True,
23 },
24 {
25 "key": "gift_note",
26 "type": "text",
27 "label": "Gift note (optional)",
28 "required": False,
29 },
30 ],
31 },
32)
33listing = resp.json()
34
35print(listing["fulfillment"]) # external
36print(listing["url"]) # https://buy.listbee.so/r7kq2xy9

Step 2: Receive the order webhook

When a buyer pays, ListBee sends an order.paid event to your webhook endpoint. The order includes checkout_data with the buyer’s responses and shipping_address parsed from the address field.

1{
2 "id": "evt_...",
3 "object": "event",
4 "type": "order.paid",
5 "created_at": "2026-04-02T10:00:00Z",
6 "data": {
7 "object": {
8 "object": "order",
9 "id": "ord_abc123",
10 "status": "paid",
11 "amount": 18900,
12 "currency": "usd",
13 "listing_id": "lst_...",
14 "listing_slug": "handmade-leather-boots",
15 "buyer_email": "buyer@example.com",
16 "checkout_data": {
17 "size": "EU 42",
18 "gift_note": "Happy birthday!"
19 },
20 "shipping_address": {
21 "line1": "123 Main St",
22 "line2": "Apt 4B",
23 "city": "Portland",
24 "state": "OR",
25 "postal_code": "97201",
26 "country": "US"
27 },
28 "fulfillment_status": "pending",
29 "paid_at": "2026-04-02T10:00:00Z"
30 }
31 }
32}

Step 3: Ship the order

After you ship, call POST /v1/orders/{id}/ship with tracking info:

1import httpx
2
3resp = httpx.post(
4 "https://api.listbee.so/v1/orders/ord_abc123/ship",
5 headers={"Authorization": "Bearer lb_..."},
6 json={
7 "carrier": "USPS",
8 "tracking_code": "9400111899223456789012",
9 "seller_note": "Ships from Portland, OR. Estimated delivery: 3-5 days.",
10 },
11)
12order = resp.json()
13
14print(order["status"]) # paid
15print(order["fulfillment_status"]) # shipped
16print(order["carrier"]) # USPS
17print(order["tracking_code"]) # 9400111899223456789012

This fires an order.shipped webhook event.

Step 4: Mark as fulfilled

When the buyer receives the product:

1import httpx
2
3resp = httpx.post(
4 "https://api.listbee.so/v1/orders/ord_abc123/fulfill",
5 headers={"Authorization": "Bearer lb_..."},
6 json={},
7)
8order = resp.json()
9
10print(order["status"]) # fulfilled
11print(order["fulfillment_status"]) # fulfilled
12print(order["fulfilled_at"]) # 2026-04-05T14:30:00Z

Order lifecycle for physical products

PENDING → PAID → (shipped) → FULFILLED
Statusfulfillment_statusMeaning
pendingnullBuyer opened checkout, hasn’t paid
paidpendingPayment confirmed, waiting for shipment
paidshippedPackage shipped, tracking info available
fulfilledfulfilledBuyer received the product

Next steps

  • Fulfillment modes — managed vs external, full comparison.
  • Checkout schema — all field types you can collect at checkout.
  • Webhooks — handle order.paid, order.shipped, and order.fulfilled events.

Copy for AI assistants

Cursor / Claude Code
1# ListBee — selling physical products
2#
3# 1. Create listing with external fulfillment + address collection:
4# POST /v1/listings {
5# name, price, fulfillment: "external",
6# checkout_schema: [
7# { key: "size", type: "select", label: "Size", required: true, options: [...] },
8# { key: "shipping_address", type: "address", label: "Address", required: true }
9# ]
10# }
11#
12# 2. Receive order.paid webhook with checkout_data + shipping_address:
13# order.checkout_data = { size: "EU 42" }
14# order.shipping_address = { line1, line2, city, state, postal_code, country }
15#
16# 3. Ship the order:
17# POST /v1/orders/{id}/ship { carrier: "USPS", tracking_code: "...", seller_note?: "..." }
18# → order.fulfillment_status: "shipped"
19# → fires order.shipped webhook
20#
21# 4. Mark fulfilled:
22# POST /v1/orders/{id}/fulfill {}
23# → order.status: "fulfilled", order.fulfillment_status: "fulfilled"
24# → fires order.fulfilled webhook
25#
26# Auth: Authorization: Bearer lb_...
27# Docs: https://docs.listbee.so/physical-products