Agent onboarding flow

This page shows the full lifecycle: account creation, email verification, Stripe setup, listing creation, and sharing the checkout URL. Each step shows the agent-human conversation alongside the API call that drives it.

This is the canonical pattern for an agent operating ListBee on behalf of a human.


Overview

Eight steps. Four require human input. Four are pure API calls the agent makes autonomously.

StepWho actsWhat happens
1AgentAsks human for email, calls POST /v1/auth/otp/start
2HumanChecks inbox, gives agent the 6-digit code
3AgentCalls POST /v1/auth/otp/verify, receives API key
4AgentReads readiness.operational — it’s false
5HumanProvides Stripe key (or goes through Connect onboarding)
6AgentSubmits Stripe key or sends Connect URL, polls until operational: true
7AgentCreates listing via POST /v1/listings
8AgentShares checkout URL with human

Step 1: Get email, request OTP

The agent asks the human for their email address, then fires an OTP request. No API key is needed — this is an unauthenticated call.

Agent says:

What’s your email address? I’ll send you a verification code.

Human says:

alex@example.com

Agent calls:

$curl -X POST https://api.listbee.so/v1/auth/otp/start \
> -H "Content-Type: application/json" \
> -d '{"email": "alex@example.com"}'
$# → 200 OK — OTP sent

Step 2: Human provides the code

The OTP is a 6-digit code sent to the email address. The agent cannot retrieve it — the human must relay it.

Agent says:

Check your inbox. There’s a 6-digit code from ListBee. What is it?

Human says:

847213


Step 3: Verify and get the API key

The agent submits the email and code. The response contains the API key and the account object — including the initial readiness state.

$curl -X POST https://api.listbee.so/v1/auth/otp/verify \
> -H "Content-Type: application/json" \
> -d '{"email": "alex@example.com", "code": "847213"}'
$# → { "api_key": "lb_...", "account": { "id": "acc_...", "readiness": { "operational": false } } }

The agent stores the API key. All subsequent requests use Authorization: Bearer lb_....


Step 4: Read readiness

After verification, readiness.operational is false. The account cannot process payments until Stripe is connected.

The response JSON contains api_key and account. Read account.readiness.next to determine what action to take:

next codekindMeaning
set_stripe_keyapiAgent can submit a Stripe key directly
connect_stripehumanHuman must complete Stripe Connect in browser

Find the action in account.readiness.actions where code matches readiness.next. If kind is "api", the agent can call it directly. If kind is "human", surface resolve.url to the user.


Step 5: Stripe setup — two paths

Path A: Human already has a Stripe key

Agent says:

To accept payments, I need your Stripe secret key. Do you have one? It starts with sk_live_ or sk_test_.

Human says:

Yes — sk_live_51abc…

Agent calls:

$curl -X POST https://api.listbee.so/v1/account/stripe-key \
> -H "Authorization: Bearer lb_..." \
> -H "Content-Type: application/json" \
> -d '{"secret_key": "sk_live_51abc..."}'
$# → account with readiness.operational: true

Path B: Human does not have a Stripe account

Agent says:

No Stripe account yet? I’ll generate a setup link. You’ll need to complete it in your browser — takes about 2 minutes.

Agent calls:

$curl -X POST https://api.listbee.so/v1/account/stripe/connect \
> -H "Authorization: Bearer lb_..."
$# → { "url": "https://connect.stripe.com/setup/..." }

Agent says:

Open this link to connect Stripe: https://connect.stripe.com/setup/… Come back here when you’re done and I’ll check if everything is ready.


Step 6: Poll until operational

After the human completes Stripe Connect, the agent polls GET /v1/account until readiness.operational is true.

$curl https://api.listbee.so/v1/account \
> -H "Authorization: Bearer lb_..."
$# Check account.readiness.operational — repeat until true

Once operational is true, the account can process payments.


Step 7: Create the listing

The agent collects listing details from the human — or generates them from context. Two paths depending on the product type.

Path A: Digital product (managed fulfillment)

Agent says:

What would you like to sell? Give me a name, price, and the file or URL you want to deliver to buyers.

Human says:

“Python Async Patterns” — $19, here’s the PDF: https://my-bucket.s3.amazonaws.com/python-async.pdf

Agent calls:

$# Create draft
$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}'
$
$# Attach 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://my-bucket.s3.amazonaws.com/python-async.pdf"}'
$
$# Publish
$curl -X POST https://api.listbee.so/v1/listings/lst_.../publish \
> -H "Authorization: Bearer lb_..."
$# → { "status": "published", "url": "https://buy.listbee.so/python-async-patterns" }

Path B: Physical product or custom service (external fulfillment)

Agent says:

What would you like to sell? I’ll set it up so you get notified when someone pays, and you handle delivery.

Human says:

Custom portrait drawings — $49. I need to know their preferred art style.

Agent calls:

$# Register a webhook to receive orders
$curl -X POST https://api.listbee.so/v1/webhooks \
> -H "Authorization: Bearer lb_..." \
> -H "Content-Type: application/json" \
> -d '{"name": "Order notifications", "url": "https://yourapp.com/webhooks/listbee", "events": ["order.paid"]}'
$
$# Create draft listing
$curl -X POST https://api.listbee.so/v1/listings \
> -H "Authorization: Bearer lb_..." \
> -H "Content-Type: application/json" \
> -d '{
> "name": "Custom Portrait Drawing",
> "price": 4900,
> "fulfillment": "external",
> "checkout_schema": [
> {"key": "style", "type": "select", "label": "Art style", "required": true, "options": ["Watercolor", "Pencil", "Digital"]},
> {"key": "description", "type": "text", "label": "Describe what you want", "required": true}
> ]
> }'
$
$# Publish
$curl -X POST https://api.listbee.so/v1/listings/lst_.../publish \
> -H "Authorization: Bearer lb_..."
$# → { "status": "published", "url": "https://buy.listbee.so/custom-portrait" }

Step 8: Share the checkout URL

Managed listing

Agent says:

Your listing is live. Share this URL with buyers: https://buy.listbee.so/python-async-patterns

When someone pays, they receive the PDF automatically by email.

External listing

Agent says:

Your listing is live. Share this URL with buyers: https://buy.listbee.so/custom-portrait

When someone pays, you’ll receive a webhook with their order details and art style preference. Fulfill the order and call the fulfill endpoint when done.


Full flow — compact version

$#!/usr/bin/env bash
$BASE="https://api.listbee.so"
$
$# Step 1: Request OTP
$read -p "Enter your email: " EMAIL
$curl -s -X POST "$BASE/v1/auth/otp/start" \
> -H "Content-Type: application/json" \
> -d "{\"email\": \"$EMAIL\"}"
$
$# Step 2: Human provides code
$read -p "Enter the 6-digit code from your inbox: " CODE
$
$# Step 3: Verify — get API key
$VERIFY=$(curl -s -X POST "$BASE/v1/auth/otp/verify" \
> -H "Content-Type: application/json" \
> -d "{\"email\": \"$EMAIL\", \"code\": \"$CODE\"}")
$
$API_KEY=$(echo "$VERIFY" | jq -r '.api_key')
$OPERATIONAL=$(echo "$VERIFY" | jq -r '.account.readiness.operational')
$NEXT_CODE=$(echo "$VERIFY" | jq -r '.account.readiness.next')
$
$# Steps 4-6: Stripe setup
$if [ "$OPERATIONAL" = "false" ]; then
$ if [ "$NEXT_CODE" = "set_stripe_key" ]; then
$ read -p "Enter your Stripe secret key (sk_live_...): " STRIPE_KEY
$ curl -s -X POST "$BASE/v1/account/stripe-key" \
> -H "Authorization: Bearer $API_KEY" \
> -H "Content-Type: application/json" \
> -d "{\"secret_key\": \"$STRIPE_KEY\"}"
$ elif [ "$NEXT_CODE" = "connect_stripe" ]; then
$ CONNECT_URL=$(curl -s -X POST "$BASE/v1/account/stripe/connect" \
> -H "Authorization: Bearer $API_KEY" | jq -r '.url')
$ echo "Open this link to connect Stripe: $CONNECT_URL"
$ read -p "Press Enter when done..."
$ fi
$
$ # Poll until operational
$ while true; do
$ ACCOUNT=$(curl -s "$BASE/v1/account" -H "Authorization: Bearer $API_KEY")
$ if [ "$(echo "$ACCOUNT" | jq -r '.readiness.operational')" = "true" ]; then
$ break
$ fi
$ sleep 5
$ done
$fi
$
$# Step 7: Create listing (managed example)
$# Create draft
$LISTING=$(curl -s -X POST "$BASE/v1/listings" \
> -H "Authorization: Bearer $API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"name": "Python Async Patterns", "price": 1900}')
$LISTING_ID=$(echo "$LISTING" | jq -r '.id')
$
$# Attach deliverable
$curl -s -X PUT "$BASE/v1/listings/$LISTING_ID/deliverable" \
> -H "Authorization: Bearer $API_KEY" \
> -H "Content-Type: application/json" \
> -d '{"type": "url", "value": "https://my-bucket.s3.amazonaws.com/python-async.pdf"}'
$
$# Publish
$PUBLISHED=$(curl -s -X POST "$BASE/v1/listings/$LISTING_ID/publish" \
> -H "Authorization: Bearer $API_KEY")
$
$# Step 8: Share URL
$echo "Your listing is live: $(echo "$PUBLISHED" | jq -r '.url')"
$echo "Fulfillment: $(echo "$PUBLISHED" | jq -r '.fulfillment')"

Next steps


Copy for AI assistants

$# ListBee — full agent onboarding flow
$#
$# STEP 1: Request OTP (no auth required)
$# POST /v1/auth/otp/start { "email": "..." }
$#
$# STEP 2: Human provides 6-digit code from inbox
$#
$# STEP 3: Verify — get API key
$# POST /v1/auth/otp/verify { "email": "...", "code": "123456" }
$# → { api_key: "lb_...", account: { id, readiness } }
$#
$# STEP 4: Check account readiness
$# account.readiness.operational: false → Stripe not connected
$# account.readiness.next: "set_stripe_key" | "connect_stripe"
$#
$# STEP 5a: Human has Stripe key → agent submits it
$# POST /v1/account/stripe-key { "secret_key": "sk_live_..." }
$#
$# STEP 5b: Human needs Stripe Connect
$# POST /v1/account/stripe/connect → { url: "https://connect.stripe.com/..." }
$#
$# STEP 6: Poll until operational
$# GET /v1/account → account.readiness.operational: true
$#
$# STEP 7a: Managed listing (digital content)
$# POST /v1/listings { name, price } → draft
$# PUT /v1/listings/{id}/deliverable { type, value } → attach content
$# POST /v1/listings/{id}/publish → live
$#
$# STEP 7b: External listing (your app delivers)
$# POST /v1/webhooks { name, url, events: ["order.paid"] }
$# POST /v1/listings { name, price, fulfillment: "external", checkout_schema?: [...] }
$# POST /v1/listings/{id}/publish → live
$#
$# STEP 8: Share listing.url with human
$#
$# Auth: Authorization: Bearer lb_...
$# Docs: https://docs.listbee.so