Skip to main content

Provision Agent from URL

Kick off an asynchronous build that turns a pasted URL into a published, chat-ready agent. The URL can be a creator channel (YouTube or Instagram), a Shopify store, or a company website — you tell the API which by passing a sourceType hint (channel URLs need no hint and are auto-detected). The request returns immediately with 202 Accepted and a buildId; you observe progress over Server-Sent Events, a polling snapshot, or an optional webhook. Once the build reaches ready, visitors chat with the agent over the anonymous chat endpoints.
This endpoint is authenticated with a brs_live_ API key — a server-side secret. NEVER ship the key to a browser. Your backend calls this endpoint and relays SSE/webhook events to the browser. The browser only ever calls the anonymous chat endpoints directly. See Authentication & rate limits.

Authentication

The key is organization-scoped; all provisioned agents and their cost bill to that org. The required scope is agents:write. A key missing the scope returns 403 insufficient_scope. See Authentication & rate limits.

Request Body

string
required
The source URL. With no sourceType, it must be a YouTube or Instagram channel URL (e.g. https://youtube.com/@channel or https://instagram.com/handle), normalized and platform-detected server-side, and an unsupported platform returns 400 unsupported_url. With sourceType set to shopify or website, any public HTTP(S) URL is accepted — see Source types & detection.
string
What kind of source url is. Omit it for a YouTube/Instagram channel (the API auto-detects those). Set it for the ecommerce/website flow:
  • shopify — a Shopify store. Ingests the product catalog plus the store’s brand/site content.
  • website — a company/organization website. Ingests the homepage and brand content (single page, not a full-site crawl).
Your frontend decides which to send — see Source types & detection. An unrecognized value is rejected by request validation.
string
The visitor’s email, for the first-party funnel claim handoff. The build is recorded against it so that after the visitor signs up (redirected with ?claim_email=<email>) the agent they just created is attached to their new account. One active unclaimed build per email — a second submit for an email that already has one returns 409 existing_unclaimed_build with the existing build, so you can offer “resume” instead of starting a duplicate.
string
A Cloudflare Turnstile token, verified server-side. Required when the platform has TURNSTILE_SECRET_KEY configured. A missing or invalid token returns 400 turnstile_failed.
string
default:"preview"
Ingestion mode.
  • preview (default) — bounded demo ingestion (~8 most-recent items, transcripts-only). Indexing finishes in seconds to about a minute.
  • full — full ingestion (deferred to a real signup; preview is the recommended path for landing-page / demo flows).
string
Optional agent intent (e.g. creator). Drives the default tool set selected for the agent.
string
Optional OpenRouter model id (e.g. openai/gpt-4o-mini). Defaults to the platform default model when omitted.
object
Optional delivery preferences.

Source types and detection

Your frontend decides sourceType and the API trusts it. There is no server-side probe of the URL to classify it — so the landing page is where the Shopify-vs-website decision is made. Recommended detection on the frontend:
  • Hostname ends in .myshopify.com → shopify (certain).
  • Custom domain (the common case — most real stores): hostname alone can’t tell you. Either ask the visitor with a toggle (“Shopify store / regular website”), which is 100% accurate and natural on an ecommerce landing, or probe GET {origin}/products.json?limit=1 from the browser (a { "products": [...] } JSON means Shopify) and fall back to the toggle on any error.
  • Anything else → website.
Mis-classifying a store as website is the safe direction: you get a homepage scrape with no catalog. Classifying a non-store as shopify fails the build. The scrape and the analysis LLM call run first and are billed; the ecommerce lane then rejects the URL (validateCredentials) and the build ends as indexing_failed, which does not name the real cause. So the toggle or the /products.json probe is worth getting right — guessing shopify is not free. Submit the store’s primary domain, not *.myshopify.com. Shopify answers 401 on the .myshopify.com address of any store that has a custom domain, so https://allbirds.myshopify.com fails where https://www.allbirds.com works. The build fails indexing_failed with a message saying exactly that (myshopify_domain_disabled from the knowledge service). A Shopify rate limit is retryable, not a bad store. Shopify rate-limits storefront reads per server IP. The platform falls back to fetching through a proxy pool when that happens; if both are refused, the build fails indexing_failed with retryable: true and a message containing store_throttled. Retry the build in a few minutes — nothing is wrong with the URL. The build is not retried automatically.
Security. This endpoint needs an API key with the agents:write scope and passes a Turnstile check, and it is rate-limited per key and per IP — but a key used from a landing page is semi-public, so treat the url as attacker-chosen.The URL you submit is SSRF-validated. A shopify or website submit whose url resolves to a private or internal host (cloud metadata, an internal service) is refused by the SSRF guard, not fetched.That guarantee covers the submitted URL, not every subsequent fetch. Media referenced by the fetched page or catalog (images[].src, <img> tags) is downloaded by the ingestion pipeline without the same guard — see CHORES.md C-164. Until that is closed, do not read this as “the server never fetches a non-public address”.

Response — 202 Accepted

string
Build identifier (bld_…). Use it to construct the stream and poll URLs.
string
queued for a fresh build, or ready immediately on a cache / handle-dedup hit (a fresh existing published agent for the same normalized handle is reused).
string
Present only when status is ready — the public slug to chat with.
string
Relative SSE URL: /v1/agents/builds/bld_…/events.
string
Relative snapshot URL: /v1/agents/builds/bld_….

Request / Response Examples

Response (202) — fresh build:
Response (202) — instant cache / handle-dedup hit:

Behaviors

  • Turnstile is verified server-side; supply a fresh token per submit.
  • URL normalization + platform detection — with no sourceType, the URL is detected as youtube / instagram / unsupported, and an unsupported platform returns 400 unsupported_url. With sourceType: "shopify" or "website", that gate does not apply — the hint is trusted (subject to the SSRF guard above).
  • Handle dedup — a fresh existing published agent for the same normalized handle is reused and returned as ready instantly, with no new build and no new cost. For a Shopify/website submit the handle is the URL’s normalized hostname.
  • Idempotency — supplying Idempotency-Key makes a double-submit return the same build instead of spawning a second one.
  • Pre-flight failures (plan limit, insufficient credits) come back as a failed build event — observed over SSE / poll / webhook — not as a synchronous HTTP error on this request.
This endpoint takes a single url, so the in-app Creator Wizard’s 3-source cap (too_many_sources on POST /bots/provision) does not apply to it.

HTTP Status Codes

Build Status & Error Model

The build progresses through a finite state machine. The complete ProvisioningStatus and ProvisioningErrorCode enums — with retryable semantics — are documented in the SSE reference and explained as concepts in Build lifecycle.