Listings

A listing is a priced product with a hosted product page. Create one with a name and price — ListBee generates a slug from the name and a product page URL.

Listings start as drafts. Attach a deliverable, then publish to go live. See Listing lifecycle for full state details.


Create a listing

POST /v1/listings requires name and price (in minor currency units — cents for USD). Returns a draft listing.

$curl -X POST https://api.listbee.so/v1/listings \
> -H "Authorization: Bearer lb_..." \
> -H "Content-Type: application/json" \
> -d '{
> "name": "Python Async Patterns",
> "price": 1900
> }'

Response:

1{
2 "object": "listing",
3 "id": "lst_...",
4 "slug": "python-async-patterns",
5 "name": "Python Async Patterns",
6 "price": 1900,
7 "status": "draft",
8 "fulfillment": "external",
9 "has_deliverable": false,
10 "url": "https://buy.listbee.so/python-async-patterns",
11 "readiness": {
12 "sellable": false,
13 "actions": [...],
14 "next": "publish_listing"
15 }
16}

The slug is derived from the name. Conflicts get a random suffix (e.g. python-async-patterns-k3f). Slugs can be changed while in draft — frozen after first publish.


Set a deliverable

Attach digital content to make the listing use managed fulfillment. Three types:

TypeInputWhat happens after purchase
fileUpload via POST /v1/files, pass the tokenBuyer gets a signed CDN download link
urlPass a URL stringBuyer is redirected to the URL
textPass a plain text stringText shown inline in confirmation

Attach a file

$# Upload the file first
$curl -X POST https://api.listbee.so/v1/files \
> -H "Authorization: Bearer lb_..." \
> -F "file=@python-async-patterns.pdf"
$# → { "object": "file", "id": "file_...", "filename": "python-async-patterns.pdf" }
$
$# Attach it to the listing
$curl -X PUT https://api.listbee.so/v1/listings/lst_.../deliverable \
> -H "Authorization: Bearer lb_..." \
> -H "Content-Type: application/json" \
> -d '{"type": "file", "token": "file_..."}'
$# → listing with fulfillment: "managed", has_deliverable: true

Attach a URL or text

$# URL deliverable
$curl -X PUT https://api.listbee.so/v1/listings/lst_.../deliverable \
> -H "Authorization: Bearer lb_..." \
> -H "Content-Type: application/json" \
> -d '{"type": "url", "value": "https://your-bucket.s3.amazonaws.com/python-async.pdf"}'
$
$# Text deliverable (license key, code, etc.)
$curl -X PUT https://api.listbee.so/v1/listings/lst_.../deliverable \
> -H "Authorization: Bearer lb_..." \
> -H "Content-Type: application/json" \
> -d '{"type": "text", "value": "LICENSE-KEY-ABCD-1234-EFGH-5678"}'

Remove a deliverable

$curl -X DELETE https://api.listbee.so/v1/listings/lst_.../deliverable \
> -H "Authorization: Bearer lb_..."
$# → listing reverts to external fulfillment

Deliverables are mutable — call PUT again to replace. Draft only — returns 409 if the listing is published.


Publish

POST /v1/listings/{id}/publish validates the listing and transitions it to published. The listing must have a name, price, and Stripe connected on the account.

$curl -X POST https://api.listbee.so/v1/listings/lst_.../publish \
> -H "Authorization: Bearer lb_..."
$# → listing with status: "published", readiness.sellable: true

If requirements are not met, returns 409 with readiness actions explaining what’s missing.

See Listing lifecycle for all state transitions (pause, resume, unpublish).


Get a listing

GET /v1/listings/{listing_id} returns a single listing by ID.

$curl https://api.listbee.so/v1/listings/lst_... \
> -H "Authorization: Bearer lb_..."

List listings

GET /v1/listings returns all listings for the authenticated account. Supports status filter and cursor pagination.

$curl "https://api.listbee.so/v1/listings?status=published&limit=20" \
> -H "Authorization: Bearer lb_..."

Update a listing

PUT /v1/listings/{listing_id} accepts any subset of fields. Only the fields you send are changed. Draft listings are fully editable. Published listings must be paused first.

$curl -X PUT https://api.listbee.so/v1/listings/lst_... \
> -H "Authorization: Bearer lb_..." \
> -H "Content-Type: application/json" \
> -d '{
> "price": 2500,
> "tagline": "Production-ready async patterns for Python 3.10+"
> }'

Delete a listing

DELETE /v1/listings/{listing_id} removes the listing, its product page, and any stored deliverable files.

$curl -X DELETE https://api.listbee.so/v1/listings/lst_... \
> -H "Authorization: Bearer lb_..."
$# → 204 No Content

Key fields

FieldTypeDescription
idstringListing ID (lst_ prefix). Used for all management operations.
slugstringURL-safe identifier derived from name. Used in product page URLs.
namestringListing title shown on the product page.
priceintegerPrice in minor currency units (cents for USD).
statusstring"draft", "published", or "paused".
fulfillmentstring"managed" or "external". Computed from deliverable presence.
has_deliverablebooleanWhether the listing has digital content attached.
checkout_schemaarray | nullCustom fields collected at checkout. Max 10.
descriptionstringFull description. Markdown supported.
taglinestringShort one-line pitch shown under the title.
highlightsstring[]Bullet points displayed prominently on the page.
ctastringBuy button label. Defaults to "Buy now".
metadataobjectKey-value store for your own data. Up to 50 keys.

Next steps


Copy for AI assistants

$# ListBee — listings API
$#
$# A listing = priced product + hosted product page.
$# All prices in minor units (cents for USD).
$# Management by ID, public lookup by slug.
$# Status: draft → published → paused
$#
$# Create draft:
$# POST /v1/listings { name, price }
$#
$# Set deliverable (managed fulfillment):
$# POST /v1/files (upload) → token
$# PUT /v1/listings/{id}/deliverable { type: "file", token: "file_..." }
$# PUT /v1/listings/{id}/deliverable { type: "url", value: "https://..." }
$# PUT /v1/listings/{id}/deliverable { type: "text", value: "..." }
$# DELETE /v1/listings/{id}/deliverable → revert to external
$#
$# Publish: POST /v1/listings/{id}/publish → published
$# Pause: POST /v1/listings/{id}/pause → paused
$# Resume: POST /v1/listings/{id}/resume → published
$# Unpublish: POST /v1/listings/{id}/unpublish → draft (0 orders only)
$#
$# Update: PUT /v1/listings/{id} { any subset of fields }
$# Delete: DELETE /v1/listings/{id} → 204
$# Get: GET /v1/listings/{id}
$# List: GET /v1/listings?status=published&limit=20&cursor=...
$#
$# Auth: Authorization: Bearer lb_...
$# Errors: RFC 9457 { type, title, status, detail, code, param }