HTML, zero JavaScript
<form method="post" action= "https://ollieleads.com/f/frm_8kq2"> <input name="email" type="email"> <button>Send</button> </form>
Your markup, your styles. The final POST is all Ollie needs.
Three ways in, one endpoint behind all of them, on every plan, Free included. Anything marked "In the pilot" isn't live yet.
<form method="post" action= "https://ollieleads.com/f/frm_8kq2"> <input name="email" type="email"> <button>Send</button> </form>
Your markup, your styles. The final POST is all Ollie needs.
// after your own checks pass ctx.waitUntil(fetch( "https://ollieleads.com/f/frm_8kq2", { method: "POST", headers: { "content-type": "application/json", "x-ollie-key": env.OLLIE_SERVER_KEY }, body: JSON.stringify(fields), signal: AbortSignal.timeout(3000) }).catch(() => {}))
Form already posts to your backend? Forward each lead with a secret server key. Your checks, emails and thank-you page keep working.
npx ollieleads connect # scans the repo, finds every form, # proposes types, asks you for avg # order value, sends a test lead
Today, paste the prompt from your Connect screen into your agent, with ollieleads.com/llms-full.txt as the reference. Keys never ship in frontend code.
A setup surface for coding agents and a read surface for sales agents, with separate scopes and the exact same authorization checks as REST. OAuth 2.1 or plain API keys for headless agents.
# setup surface create_brand · create_form · get_form_schema add_allowed_origin · verify_integration # read surface list_brands · list_forms · list_leads get_lead · get_contact · get_usage
Every error is self-describing with a machine-actionable fix, and every call is safe to retry.
{"error": "origin_not_allowed", "fix": "call add_allowed_origin"}
lead.submitted lead.left_early lead.ready lead.updated contact.created consent.updated form.silent integration.failed
HMAC signatures, at-least-once delivery with stable event IDs, exponential backoff and a replay facility. Events carry IDs only; details come from an authenticated read with consent context, form type and fill time included.
Visitor text arrives wrapped as untrusted_visitor_input, so your agent treats it as data, never
as instructions. lead.ready fires for submitted, consent-eligible Sales, Quote and Contact leads
by default.
ol_live_7f3ad91c… # server key: secret, counts ol_test_connect # tagged [TEST], never counts
Server keys are per brand, shown once, stored only as a hash and revocable. They can add leads, never read them. Every brand is isolated down to row-level security in the database.
Press Send a test lead on the Connect screen, or send one with the test key. Notifications reach Slack and Discord in seconds, and usage is counted exactly once per lead.
Yes. A plain HTML POST to your endpoint is fully supported. The SDK is only for progressive capture on multi-step forms and session continuity.
No. Keep your handler, your emails and your thank-you page, and forward each lead from your server with a server key. Use a 3 second timeout, so your form never waits on Ollie.
A plain HTML form shows the visitor what they typed, so nothing is lost. From your own server, a short timeout means your form carries on. Every post can carry an idempotency key, so a retry never counts twice.
It ships in the pilot, with a setup surface for coding agents and a read surface for sales agents and the same authorization as the REST API. Today, coding agents connect forms from the prompt on the Connect screen.
Send with the test key ol_test_connect, or press Send a test lead on the Connect screen. Test leads are tagged [TEST], go through the whole loop with notifications marked as tests, and never count.