Idempotency

Send an Idempotency-Key header with any POST request. If you use the same key within 24 hours, ListBee returns the original cached response instead of executing the request again.

Idempotency keys expire after 24 hours. After expiry, the same key is treated as a new request and will execute again.

Idempotency-Key: <unique-string>

When to use it

Use an idempotency key whenever you are not sure whether a request succeeded.

Common scenarios:

  • Network timeout before you receive a response
  • Connection reset mid-request
  • Client crash after sending but before receiving
  • Retry logic that may fire even when the original succeeded

Without an idempotency key, retrying a POST /v1/listings after a timeout creates a second listing. With one, the retry returns the original listing.


Which endpoints support it

All POST endpoints under /v1/* accept Idempotency-Key. This includes:

  • POST /v1/account/signup
  • POST /v1/account/verify
  • POST /v1/account/stripe-key
  • POST /v1/account/stripe/connect
  • POST /v1/api-keys
  • POST /v1/listings

GET, PUT, and DELETE requests are inherently idempotent and do not use the header.


How it works

  1. First request with key abc-123 → request executes, response cached for 24 hours.
  2. Second request with same key abc-123 and same body → cached response returned, no side effects.
  3. Request with key abc-123 and a different body → 409 idempotency_conflict.

The key is scoped to your API key. Two different accounts can use the same idempotency key without conflict.


Example

Use a UUID as the idempotency key. Generate it once before the first attempt and reuse it on every retry.

1import httpx
2import uuid
3
4BASE = "https://api.listbee.so"
5API_KEY = "lb_..."
6
7# Generate key once — reuse on every retry
8idempotency_key = str(uuid.uuid4())
9
10payload = {
11 "name": "Python Async Patterns",
12 "price": 1900,
13 "deliverable": "https://my-bucket.s3.amazonaws.com/python-async.pdf",
14}
15
16# Retry up to 3 times with the same idempotency key
17for attempt in range(3):
18 try:
19 resp = httpx.post(
20 f"{BASE}/v1/listings",
21 headers={
22 "Authorization": f"Bearer {API_KEY}",
23 "Idempotency-Key": idempotency_key,
24 },
25 json=payload,
26 timeout=10.0,
27 )
28 resp.raise_for_status()
29 listing = resp.json()
30 print(listing["url"]) # https://buy.listbee.so/m3pr5tw1
31 break
32 except (httpx.TimeoutException, httpx.NetworkError) as exc:
33 if attempt == 2:
34 raise
35 print(f"Attempt {attempt + 1} failed: {exc}. Retrying...")

Conflict response

If you send the same key with a different request body, ListBee returns 409 Conflict:

1{
2 "type": "https://docs.listbee.so/errors/idempotency-conflict",
3 "title": "Idempotency conflict",
4 "status": 409,
5 "detail": "An idempotency key was reused with a different request body.",
6 "code": "idempotency_conflict",
7 "param": null
8}

This protects against accidentally reusing a key for a different operation.


Next steps

  • Rate limits — idempotent retries hit the cache, not the rate limiter.
  • Errors — handle idempotency_conflict (409) when keys are reused with different bodies.

Copy for AI assistants

Cursor / Claude Code
1# ListBee — idempotency
2#
3# Header: Idempotency-Key: <unique-string>
4# Applies to: all POST /v1/* endpoints
5# Duration: 24 hours
6#
7# Behavior:
8# Same key + same body → cached response (no side effects)
9# Same key + diff body → 409 idempotency_conflict
10# Different key → new request executes normally
11#
12# Best practice: generate a UUID before the first attempt, reuse on every retry
13# import uuid; key = str(uuid.uuid4())
14#
15# When to use: any time a timeout or network error means you don't know
16# if the original request succeeded — listing creation, account signup, etc.
17#
18# Key is scoped to your API key — no cross-account conflicts
19#
20# Auth: Authorization: Bearer lb_...
21# Docs: https://docs.listbee.so/idempotency