AgentStorybook API

v1 · Create storybooks programmatically from your CRM, a spreadsheet, or any tool.

How do I authenticate?

Send your API key as a bearer token on every request. Generate the key in your dashboard under Account → API Access:

Authorization: Bearer asb_live_xxxxxxxxxxxx

Keep keys secret — anyone with a key can create storybooks on your account. Rate limit: 60 requests/minute.

Which plans can use the API?

Team and Brokerage. A key on any other plan authenticates fine and then gets 403 plan from the create endpoint, because the key is real and the entitlement is not — worth distinguishing when you are debugging, since 401 and 403 mean two different fixes.

Verify before you build: GET /api/v1/me returns the plan the key resolves to. If it does not say team or brokerage, creation will fail no matter how well-formed the body is.

What are the rate limits?

60 requests per minute, per account, in a fixed window. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining, so you can back off before you are cut off rather than after.

The window is fixed, not rolling: it resets on the minute rather than 60 seconds after your first call. A burst that straddles the boundary can therefore send up to 120 requests in a 60-second span without a 429. Do not build on that — it is an artifact, not a promise.

How do I create a storybook?

Send one POST with the client, the address and the dates. Everything else has a default, and the cover is generated for you.

POST https://agentstorybook.ai/api/v1/storybooks

Leave the cover to us. By default, when no clientPhotoUrl is supplied we feature the agent — illustrated from the headshot & sign saved in the account — standing proudly by the home (their own billboard). Provide a clientPhotoUrl to star the client instead, or set coverStar explicitly (agent, client, or home). Add a housePhotoUrl for the home (sellers fall back to Street View), or supply a finished coverImageUrl to skip generation entirely. Cover generation can take 30–60 seconds.

Fields

FieldRequiredNotes
typeyes"seller" or "buyer"
addressyesFull street address. Used for the auto cover.
clientsnoFull display name, used as-is. e.g. "John & Sarah Smith"
client1, client2noTwo owner names from your CRM. We format smartly: shared surname → "John & Sarah Smith"; different → "John Smith & Sarah Jones". Ignored if clients is set.
agentnoAgent name shown on the storybook
brandnoBrokerage / brand name. Printed on the SOLD sign only when you have not uploaded a yard-sign photo in Account.
datesnoObject. Seller: listing, list, prePhoto, photo, contract, closing. Buyer: consultation, seeHomes, contract, closing. ISO dates (2026-07-01).
clientPhotoUrlnoPublic image URL of the client(s). We illustrate their likeness on the cover. Omit to feature the agent by default (or set coverStar).
coverStarnoWho the cover features: agent (from the account headshot + sign), client (requires clientPhotoUrl), or home. Defaults to client when a client photo is given, otherwise agent (falling back to home if no headshot is on file).
housePhotoUrlnoPublic image URL of the home. Sellers fall back to Street View if omitted.
coverImageUrlnoSupply your own cover image instead of auto-generating.
waitForCovernoDefault true (waits ~30–60s and returns when the cover is ready). Set false to return immediately with coverStatus:"generating" — recommended for Zapier and other timeout-sensitive callers.
idempotencyKeynoReuse the same value to avoid duplicates on retries.

Example

curl -X POST https://agentstorybook.ai/api/v1/storybooks \
  -H "Authorization: Bearer asb_live_xxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "seller",
    "address": "123 Main St, Dallas, TX 75201",
    "clients": "John & Sarah Smith",
    "agent": "Thomas Eaves",
    "dates": { "listing": "2026-07-01", "closing": "2026-08-15" },
    "idempotencyKey": "crm-deal-48213"
  }'

Response 201 Created

{
  "slug": "123-main-st",
  "type": "seller",
  "clientUrl": "https://agentstorybook.ai/stories/123-main-st?token=...",
  "publicUrl": "https://agentstorybook.ai/stories/123-main-st",
  "coverGenerated": true,
  "coverStatus": "ready",
  "status": "ready"
}

What else can I call?

Four more endpoints, all read or delete — creation is the only write.

GET /api/v1/storybooks — list your storybooks.
GET /api/v1/storybooks?slug=123-main-st — fetch one.
DELETE /api/v1/storybooks?slug=123-main-st — delete one.
GET /api/v1/me — verify a key; returns your plan.

How do I stop retries creating duplicates?

Send an idempotencyKey and reuse the exact same value on every retry of the same logical create. The first call does the work; any repeat within 24 hours returns the original response with idempotentReplay: true added, and creates nothing.

Use something stable from your own system — a CRM deal id, a spreadsheet row id — not a timestamp or a random value, which would make each retry look like a new storybook. This matters more than it sounds: a create can take 30 to 60 seconds while the cover generates, which is long enough for an HTTP client, a queue worker or a Zapier step to give up and try again on a request that in fact succeeded.

Why does creating a storybook take 30–60 seconds?

Because the cover is illustrated at create time, not pulled from a template. That is the slowest thing the endpoint does, and by default the request waits for it and returns coverStatus: "ready".

If your caller has a shorter timeout than that — Zapier actions cut off around 30 seconds — send waitForCover: false. The call returns immediately with coverStatus: "generating" and the storybook is created; the cover lands on its own a minute later. Poll GET /api/v1/storybooks?slug=... if you need to know when it is done. The client link works either way; it simply shows the cover once it exists.

What do the errors mean?

Every failure returns the same shape — { "error": "code", "message": "..." } — so you can branch on error and show message to whoever is watching the integration.

HTTPerrorWhat actually happened
401unauthorizedNo key, or a key that has been revoked. Check the Authorization header is Bearer plus the key, with nothing extra.
400invalidA required field is missing or the wrong shape. message names the field.
403planThe key is valid but the account is not on Team or Brokerage. See the plans question above.
404not_foundNo storybook with that slug on your account. A slug belonging to another account returns 404 rather than 403, on purpose — it does not confirm the storybook exists.
405method_not_allowedThe endpoint does not take that verb.
429rate_limitedMore than 60 requests in the current minute. Wait for the window to roll over.
500server_errorOur side. Safe to retry with the same idempotencyKey.

Questions? Reply to your AgentStorybook welcome email.