How did you hear about us?
const url = 'https://stitch-collector-dev.magic-blocks.workers.dev/v1/declared';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"identity":{"email":"borrower@example.com"},"declared_source":"I heard you on a podcast","captured_via":"voice_agent","reference":"transcript-4471"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://stitch-collector-dev.magic-blocks.workers.dev/v1/declared \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "identity": { "email": "borrower@example.com" }, "declared_source": "I heard you on a podcast", "captured_via": "voice_agent", "reference": "transcript-4471" }'One door for a declared source, from a website form, a loan officer’s tool, or a voice agent — directly or through a middleware. Nothing here earns credit: the answer is counted and cross-tabbed against what was tracked; it never becomes a touchpoint. Two doors: with a key, any identity and captured_via; from a registered page without a key, only declared_source and the browser’s own cookie (or anon_id), which must already be bound to a person. An answer nobody can attach to a person is refused, not parked.
Authorizations
Section titled “Authorizations ”- webhookKey
- None
Request Body required
Section titled “Request Body required ”What the person said when asked how they heard about us. Either identity grammar is accepted: identity {…} as /v1/conversion speaks it, or anon_id + traits + external_ids as /v1/identify does. With a key, any identity; from a page without a key, only declared_source, a reference, and a browser this collector has already bound to a person.
object
Free text. Becomes one of a dozen coarse buckets.
object
The contact id in whatever is the system of record for contacts (today, likely the CRM): the spine id. octopus_id and los_contact_id are accepted as the same thing.
The visitor’s anonymous id from the first-party cookie.
Normalised and SHA-256’d inside the Worker before anything touches storage. The plaintext exists only for the request.
object
Any formatting; normalised to E.164 before hashing.
Any recognised key works; send what you have. Unrecognised keys are ignored. anon_id is the browser’s cookie value, read server-side from the _bid cookie or minted by the SDK.
object
The contact id in whatever is the system of record for contacts (today, likely the CRM): the spine id. octopus_id and los_contact_id are accepted as the same thing.
The visitor’s anonymous id from the first-party cookie.
Keyed callers only.
Keyed callers only; a page is always form.
A transcript or form id. Keep it: a surprising bucket is only believable if someone can read what was said.
Keyed callers only; epoch milliseconds.
Responses
Section titled “ Responses ”What was recorded, so a form can confirm rather than promise.
object
The coarse bucket the answer landed in, e.g. radio_or_podcast, social, search, referral.
The phrase that decided it.
Example
{ "person_id": "01fa113c-ae40-4671-851f-29707ed6c2da", "bucket": "radio_or_podcast", "matched": "podcast"}Malformed JSON or a payload missing what the endpoint needs. The body says which.
object
What was wrong, in a sentence. A 401 carries unauthorized and nothing more.
Example generated
{ "error": "example"}No key and not a registered origin; or a page sent identity fields only a keyed caller may send. Nothing was written.
object
What was wrong, in a sentence. A 401 carries unauthorized and nothing more.
Example
{ "error": "unauthorized"}Only the method shown is served.