開発者向け

Echoをあらゆるツールに接続できます。

APIキーでアクション、リード、プロンプト、プレイブックを読み取り・変更できます。署名付きWebhookでイベントを即時に受け取ることも、EchoのZapierアプリやn8nノードを使ってコードなしで連携することもできます。

基本情報

以下のアドレスはすべてhttps://echo-aeo.com/api/v1から始まります。

Keys
Make a key in Echo under Settings → API and webhooks (the workspace owner can) and send it as “Authorization: Bearer echo_…”. A key works for one workspace, with the scopes you gave it; write includes read.
Limits
120 requests a minute per key; after that Echo answers 429 with Retry-After. Plan limits (leads, playbook runs) apply as in the app.
Answers
JSON with snake_case fields and ISO times. Lists are { data, next_cursor }: pass next_cursor as cursor for the next page. Errors are { error: { code, message } } with code unauthorized, forbidden, not_found, invalid_request, plan_limit, rate_limited or server_error.
Versions
Everything is under /api/v1. Fields may be added; nothing is removed or renamed within v1.
curl https://echo-aeo.com/api/v1/actions?brand_id=YOUR_BRAND_ID \
  -H "Authorization: Bearer echo_YOUR_KEY"

The workspace

Who the key belongs to. Zapier and n8n use it to test a key.

GET/me

The key's workspace, its name and scopes, and the workspace's brands.

{ "workspace": { "id": "ws_…", "name": "Fernwick" }, "key": { "id": "key_…", "name": "Zapier", "scopes": ["leads:write"] },
  "brands": [{ "id": "b_x7…", "name": "Fernwick", "domain": "fernwick.example" }] }

GET/brands

The workspace's brands.

{ "data": [{ "id": "b_x7…", "name": "Fernwick", "domain": "fernwick.example", "created_at": "…" }], "next_cursor": null }

Actions

The to-do list every part of Echo feeds: what to change on the website, pages to build, where to get mentioned, follow-ups.

GET/actionsactions:read

A brand's actions, newest first.

brand_id
query, required. The brand's id (GET /brands).
status
query. todo, doing, done or dismissed.
limit
query. 1–100, 25 by default.
cursor
query. next_cursor from the page before.
{ "data": [{
  "id": "Hh3kP9…", "brand_id": "b_x7…", "title": "Add a comparison page with Tallybird",
  "kind": "create_page", "impact": "high", "status": "todo", "source": "ai",
  "url": "https://echo-aeo.com/app/actions?brand=b_x7…&action=Hh3kP9…",
  "assignee_email": "priya@fernwick.example", "due_date": "2026-10-10",
  "detail": "…", "created_at": "2026-09-28T06:02:11.000Z", "done_at": null
}], "next_cursor": "eyJ0Ijo…" }

GET/actions/{id}actions:read

One action.

id
path, required. The action's id.
{
  "id": "Hh3kP9…", "brand_id": "b_x7…", "title": "Add a comparison page with Tallybird",
  "kind": "create_page", "impact": "high", "status": "todo", "source": "ai",
  "url": "https://echo-aeo.com/app/actions?brand=b_x7…&action=Hh3kP9…",
  "assignee_email": "priya@fernwick.example", "due_date": "2026-10-10",
  "detail": "…", "created_at": "2026-09-28T06:02:11.000Z", "done_at": null
}

POST/actionsactions:write

Adds a “Follow up” action to a brand's board.

brand_id
body, required. The brand's id.
title
body, required. Up to 180 characters.
detail
body. What to do, up to 2,000 characters.
impact
body. high, medium (default) or low.
due_date
body. YYYY-MM-DD.
assignee_email
body. A member of the workspace.
{
  "id": "Hh3kP9…", "brand_id": "b_x7…", "title": "Add a comparison page with Tallybird",
  "kind": "create_page", "impact": "high", "status": "todo", "source": "ai",
  "url": "https://echo-aeo.com/app/actions?brand=b_x7…&action=Hh3kP9…",
  "assignee_email": "priya@fernwick.example", "due_date": "2026-10-10",
  "detail": "…", "created_at": "2026-09-28T06:02:11.000Z", "done_at": null
}

PATCH/actions/{id}actions:write

Changes an action's status, due date or assignee. Marking it done sends action.done.

status
body. todo, doing, done or dismissed.
due_date
body. YYYY-MM-DD, or null to clear.
assignee_email
body. A member's email, or null to unassign.
{
  "id": "Hh3kP9…", "brand_id": "b_x7…", "title": "Add a comparison page with Tallybird",
  "kind": "create_page", "impact": "high", "status": "todo", "source": "ai",
  "url": "https://echo-aeo.com/app/actions?brand=b_x7…&action=Hh3kP9…",
  "assignee_email": "priya@fernwick.example", "due_date": "2026-10-10",
  "detail": "…", "created_at": "2026-09-28T06:02:11.000Z", "done_at": null
}

Leads

People who agreed to hear from the brand. Echo keeps only them, so adding one needs your word that they agreed.

GET/leadsleads:read

The workspace's leads, newest first.

email
query. Find one lead by email.
limit
query. 1–100, 25 by default.
cursor
query. next_cursor from the page before.
{ "data": [{
  "id": "Lq81…", "email": "ines@quietharbour.example", "first_name": "Ines", "last_name": "Duarte",
  "company": "Quiet Harbour Studio", "website": "quietharbour.example", "source": "api",
  "can_email": true, "blocked_reason": null, "created_at": "2026-09-29T09:14:02.000Z"
}], "next_cursor": null }

GET/leads/{id}leads:read

One lead.

id
path, required. The lead's id.
{
  "id": "Lq81…", "email": "ines@quietharbour.example", "first_name": "Ines", "last_name": "Duarte",
  "company": "Quiet Harbour Studio", "website": "quietharbour.example", "source": "api",
  "can_email": true, "blocked_reason": null, "created_at": "2026-09-29T09:14:02.000Z"
}

POST/leadsleads:write

Adds a lead, or updates the one with that email (201 when new, 200 when updated).

email
body, required. Their email address.
consent
body, required. Your confirmation that they agreed to hear from you. Without it Echo refuses the lead.
first_name, last_name, company, website
body. What you know about them.
email_campaign_id
body. Adds them to an email campaign (GET /email-campaigns).
{
  "id": "Lq81…", "email": "ines@quietharbour.example", "first_name": "Ines", "last_name": "Duarte",
  "company": "Quiet Harbour Studio", "website": "quietharbour.example", "source": "api",
  "can_email": true, "blocked_reason": null, "created_at": "2026-09-29T09:14:02.000Z",
  "created": true, "added_to_campaign": null
}

GET/email-campaignsleads:read

The workspace's email campaigns, to add leads to.

{ "data": [{ "id": "c_…", "name": "AI score follow-up", "status": "active", "brand_id": "b_x7…", "created_at": "…" }], "next_cursor": null }

Newsletters and lists

Newsletter issues with their results, and the mailing lists people subscribe to. Subscribing someone needs your word that they agreed to get the newsletter.

GET/newslettersnewsletters:read

A brand's newsletter issues (the newest 100) with who they went to and their results.

brand_id
query, required. The brand's id (GET /brands).
{ "data": [{ "id": "n_…", "title": "October roundup", "subject": "What's new in October", "status": "sent", "list_ids": ["l_…"], "segment_id": null, "scheduled_at": null, "sent_at": "…", "recipients": 1240, "sent": 1236, "delivered": 1229, "clicked": 212, "clicks": 301, "opened": null, "unsubscribed": 4, "bounced": 3, "complained": 0, "web_url": "https://echo-aeo.com/p/fernwick/newsletter/october-roundup", "created_at": "…" }], "next_cursor": null }

GET/listsnewsletters:read

A brand's mailing lists with their subscribers.

brand_id
query, required. The brand's id (GET /brands).
{ "data": [{ "id": "l_…", "name": "Product news", "description": "Monthly", "public": true, "subscribed": 1240, "unsubscribed": 31, "created_at": "…" }], "next_cursor": null }

POST/lists/{id}/contactsnewsletters:write

Subscribes someone to a list: adds them as a contact (or updates the one with that email) and puts them on the list. Someone who unsubscribed stays unsubscribed.

email
body, required. Their email address.
consent
body, required. Your confirmation that they agreed to get the newsletter.
first_name, last_name, company
body. What you know about them.
{ "contact_id": "ld_…", "list_id": "l_…", "status": "subscribed", "created": true, "joined": true }

DELETE/lists/{id}/contactsnewsletters:write

Unsubscribes someone from a list.

email
query, required. Their email address.
{ "unsubscribed": true }

Prompts and AI visibility

The questions Echo asks AI assistants for a brand, and how often the answers name it.

GET/promptsprompts:read

A brand's prompts with their topic, intent, market and whether they're tracked.

brand_id
query, required. The brand's id (GET /brands).
{ "data": [{ "id": "p_…", "text": "Best CRM for a small agency?", "topic": "CRM for small teams", "intent": "commercial", "market_id": "m_…", "active": true, "created_at": "…" }], "next_cursor": null }

GET/metricsmetrics:read

AI visibility for a period: share of answers naming the brand, share of voice, position and tone, for the brand and each competitor, and per day.

brand_id
query, required. The brand's id (GET /brands).
from, to
query. YYYY-MM-DD; the last 30 days by default.
engine
query. all (default), chatgpt, perplexity, gemini, claude, google_aio, google_ai_mode or grok.
market
query. A market's id.
{ "brand_id": "b_x7…", "from": "2026-08-31", "to": "2026-09-29", "engine": "all",
  "brand": { "visibility": 0.41, "share_of_voice": 0.22, "avg_position": 2.3, "positive_share": 0.64, "mentions": 412, "answers": 1004, "citations": 88 },
  "competitors": [{ "id": "…", "name": "Tallybird", "domain": "tallybird.example", "visibility": 0.58, … }],
  "days": [{ "date": "2026-09-29", "answers": 40, "visibility": 0.43 }] }

Landing pages

The pages Echo hosts for a brand (More → Landing pages), with their address and results since they went live.

GET/landing-pagespages:read

A brand's landing pages: title, address, status, views (the Echo tag) and confirmed sign-ups from their lead forms.

brand_id
query, required. The brand's id (GET /brands).
{ "data": [{ "id": "lp_…", "title": "Fernwick vs. Tallybird", "url": "https://go.fernwick.example/fernwick-vs-tallybird", "status": "published",
  "views": 1240, "leads": 38, "campaign_id": "mc_…", "published_at": "2026-09-20T10:02:00.000Z", "created_at": "…" }], "next_cursor": null }

Experiments

A brand's conversion tests (More → Landing pages → Experiments): landing page, lead form and before-and-after tests, each version's visitors and sign-ups, and the result.

GET/experimentsexperiments:read

A brand's tests, newest first: what's tested, status, the verdict in words, each version's visitors, sign-ups, confirmed sign-ups and chance to beat the original, the result and the learning.

brand_id
query, required. The brand's id (GET /brands).
{ "data": [{ "id": "ex_…", "name": "Free audit instead of a demo", "kind": "page", "focus": "offer", "status": "finished", "result": "won",
  "verdict": "Version B wins: 97% chance it's better, +38% sign-ups per visitor.", "learning": "A smaller first step works better.",
  "versions": [{ "key": "A", "name": "Original", "visitors": 912, "sign_ups": 29, "confirmed": 22, "chance_to_beat_original": null },
    { "key": "B", "name": "Version B", "visitors": 928, "sign_ups": 42, "confirmed": 33, "chance_to_beat_original": 0.97 }],
  "page_id": "lp_…", "form_id": null, "campaign_id": null, "started_at": "2026-09-01T09:00:00.000Z", "ended_at": "2026-09-19T05:00:00.000Z", "created_at": "…" }], "next_cursor": null }

Outreach, partners and events

A brand's outreach (pitches, listing and review requests and community replies: Market intel → Mentions → Outreach), partnerships and own events (More → Partners and events), with their stage, next step and results, and its contacts. Echo never emails or posts for these: people send and post from their own mail and accounts.

GET/relationsrelations:read

A brand's items, newest first: programme, format, stage (open, won or lost), next step and date, owner, contact, outlet or community, campaigns, live coverage pieces and the tracking link's visits and sign-ups.

brand_id
query, required. The brand's id (GET /brands).
programme
query. media, partner, event or community; leave out for all.
{ "data": [{ "id": "ri_…", "programme": "media", "format": "podcast", "title": "Pitch the Agency Ops Podcast on pipeline reviews", "stage": "agreed", "state": "open",
  "next_step": "Send three talking points", "next_date": "2026-10-08", "owner_user_id": "u_…", "contact": { "id": "rc_…", "name": "Robin Vale", "outlet": "Agency Ops Podcast" },
  "place": "Agency Ops Podcast", "url": "https://agencyops.example", "event_at": null, "campaign_ids": ["mc_…"], "coverage": 0, "visits": 0, "sign_ups": 0,
  "result_at": null, "created_at": "2026-09-22T09:12:00.000Z", "updated_at": "…" }], "next_cursor": null }

GET/relation-contactsrelations:read

A brand's contacts (Mentions → Contacts): journalists, podcast hosts, partners and community members, with role, outlet, email, website, topics and how many items they're on.

brand_id
query, required. The brand's id (GET /brands).
{ "data": [{ "id": "rc_…", "name": "Robin Vale", "role": "Host", "outlet": "Agency Ops Podcast", "email": "robin@agencyops.example", "website": "https://agencyops.example",
  "topics": ["agency operations", "sales"], "items": 1, "source": "csv", "created_at": "2026-09-20T08:00:00.000Z" }], "next_cursor": null }

Competitor ads

The ads a brand's competitors run on Meta and Google, from the platforms' public ad libraries (Competitive intel → Ads). Meta shows product ads only for ads shown in the EU and the UK. No spend or results: the libraries don't publish them.

GET/competitor-adscompetitors:read

Every competitor's ads Echo keeps (running ones and those stopped in the last 12 months): platform, format, texts (Meta), preview picture (Google), where it links, countries, first and last seen, days running, its theme and its link in the ad library.

brand_id
query, required. The brand's id (GET /brands).
{ "data": [{ "id": "ca_…", "competitor": { "id": "c_…", "name": "Tallybird", "domain": "tallybird.example" }, "platform": "meta", "format": "image",
  "headline": "Client reports in one click", "body": "Stop building reports by hand…", "landing_url": "https://tallybird.example", "preview_image_url": null,
  "library_url": "https://www.facebook.com/ads/library/?id=…", "countries": ["DE", "NL"], "first_seen": "2026-07-02T00:00:00.000Z", "last_seen": "2026-09-30T08:00:00.000Z",
  "stopped_at": null, "running": true, "days_running": 91, "theme": "Client reporting" }], "next_cursor": null }

Mentions

Where people talk about the brand and its competitors on the web (Market intel → Mentions, Phase 60): threads, reviews and posts from the pages AI answers cite, Google, Google Alerts, Hacker News and Stack Overflow. Read only: Echo never posts; the team replies from their own accounts.

GET/mentionsmentions:read

A brand's mentions, newest first: link, site, title, snippet, the author's public handle when the source gives one, date, sentiment, whether it names the brand and which competitors, whether it's a question, whether AI answers cite it and which assistants, and its status (new, seen, answered, ignored).

brand_id
query, required. The brand's id (GET /brands).
site
query. Only one site, e.g. reddit.com.
sentiment
query. positive, neutral or negative.
cited
query. 1 = only pages AI answers cite.
status
query. all (default), open, new, seen, answered or ignored.
limit
query. Up to 500 (default 100).
{ "data": [{ "id": "lm_…", "url": "https://www.reddit.com/r/agencies/comments/abc123", "site": "reddit.com", "site_label": "Reddit",
  "title": "Which CRM do small agencies use?", "snippet": "We tried Tallybird but…", "author": null, "published_at": "2026-09-28", "sentiment": "neutral",
  "names_brand": false, "competitors": ["Tallybird"], "question": true, "cited": true, "cited_by": ["chatgpt", "perplexity"], "status": "new" }], "next_cursor": null }

Brand assets

Who outside the team has access to Brand assets, and the “Request files” links (Phase 56). Read only: inviting a guest or making a request is a person's click in Echo.

GET/guestsassets:read

The workspace's guests (freelancers and agencies invited to chosen collections): email, name, state (invited, active or ended), their collections with whether they can upload, when their access ends and when they were last seen. Optional brand_id: only guests with collections of that brand.

brand_id
query. Only guests with collections of this brand.
{ "data": [{ "id": "g_…", "email": "sam@studio.example", "name": "Sam Park", "state": "active",
  "collections": [{ "id": "col_…", "name": "Autumn campaign", "brand_id": "b_x7…", "can_upload": true }],
  "access_ends_at": null, "accepted_at": "2026-09-30T10:00:00.000Z", "last_seen_at": "2026-09-30T10:05:00.000Z", "created_at": "…" }], "next_cursor": null }

GET/file-requestsassets:read

A brand's file requests: title, note, the link, the collection files go into, state (open, closed, expired or full), which kinds of files it takes, its limits, how many files came in and how many still wait for review.

brand_id
query, required. The brand's id (GET /brands).
{ "data": [{ "id": "fr_…", "title": "Your logo as SVG", "note": "For the partner page", "url": "https://echo-aeo.com/r/…",
  "collection": { "id": "col_…", "name": "Partner logos" }, "state": "open", "has_password": false, "file_kinds": ["images"], "max_files": 50,
  "max_file_bytes": 524288000, "files_received": 3, "files_to_review": 1, "last_received_at": "…", "expires_at": "2026-10-30T00:00:00.000Z", "created_at": "…" }], "next_cursor": null }

Playbooks and events

Playbooks run by themselves when something happens. Start one for a lead from your own tools, or read the events of the last 30 days.

GET/playbooksplaybooks:read

A brand's playbooks.

brand_id
query, required. The brand's id (GET /brands).
{ "data": [{ "id": "pb_…", "name": "Welcome new form leads", "trigger": "form.submitted", "enabled": true, "brand_id": "b_x7…", "created_at": "…" }], "next_cursor": null }

POST/playbooks/{id}/runsplaybooks:write

Runs a playbook about a person (form sign-ups, AI score sign-ups, replies) for one of your leads. Counts toward the plan's runs.

lead_id
body, required. The lead's id.
{ "id": "run_…", "playbook_id": "pb_…", "status": "done" }

GET/eventsplaybooks:read

Events of the last 30 days that a playbook or webhook listened to, newest first.

type
query. One event type (below).
limit
query. 1–100, 25 by default.
sample
query. With type: a made-up event when there's none yet (for testing a Zap).
{ "data": [ { "id": "evt_…", "type": "form.submitted", … } ], "next_cursor": null }

Webhooks

Zapier and n8n subscribe here when a Zap or workflow with an Echo trigger is switched on, and unsubscribe when it's switched off. Your own code can too.

GET/webhookswebhooks:read

The workspace's webhooks.

{ "data": [{ "id": "wh_…", "url": "https://hooks.zapier.com/…", "events": ["form.submitted"], "brand_id": null, "enabled": true, … }], "next_cursor": null }

POST/webhookswebhooks:write

Adds a webhook. Its signing secret is in the answer, once.

url
body, required. A public https address.
events
body. Event types to send (or one as event).
brand_id
body. Only this brand's events.
{ "id": "wh_…", "url": "https://hooks.zapier.com/…", "events": ["lead.replied"], "enabled": true, "secret": "whsec_…", … }

DELETE/webhooks/{id}webhooks:write

Removes a webhook.

id
path, required. The webhook's id.
{ "id": "wh_…", "deleted": true }

イベント

プレイブックの開始条件とWebhookの送信内容。各配信はPOSTで、イベントのid、type、time、workspace、brand、dataをJSON形式で送信します。

form.submitted
A lead form is submitted. When someone confirms their email after filling in one of the brand's lead forms (double opt-in), or when a connected form on your own website (Framer, Webflow, a webhook) sends a submission with an email address. Either way they're an opted-in lead. Use the form name in a condition to tell forms apart.
score.signup
Someone runs the free AI score. When someone runs the free AI score on the brand's website. They asked for a scan, not for emails, so email steps skip them unless they're already an opted-in lead.
lead.replied
A lead replies to an email campaign. When a lead answers a mail of an email campaign. Out-of-office replies don't count.
company.visited
A company views a page. When Company visitors sees a company view a page of the website, once per company, page and day.
account.signal
A target account shows a buying signal. When a target account shows a new buying signal: a visit, hiring, funding, a new leader, news, an event or a tech change.
action.created
An action is created. When Echo or a teammate adds an action to the board.
action.done
An action is done. When an action is marked done.
project.created
A project is created. When a teammate creates a project (Home → Projects) or turns one of Echo's suggested projects into one. Once per project.
project.done
A project is done. When a project is marked done, with its visibility on its prompts before it started and in the last 14 days. Once per project.
campaign.started
A campaign starts. When a campaign's start date arrives.
campaign.ended
A campaign ends. When a campaign's end date has passed.
page.published
A landing page is published. When a landing page goes live, and each time a new version of it is published.
experiment.started
A test starts. When a landing page, lead form or before-and-after test starts (More → Landing pages → Experiments).
experiment.finished
A test has a result. When a test ends: Echo called it (a new version won, the original won, or no clear difference after 6 weeks) or someone stopped it.
competitor.ad_started
A competitor starts an ad. When Echo's weekly check finds a new ad a watched competitor runs on Meta or Google (from the platforms' public ad libraries).
competitor.ad_stopped
A competitor stops an ad. When Echo's weekly check sees that one of a watched competitor's ads stopped running, with how many days it ran.
asset.uploaded
A file is uploaded to Brand assets. When a file or a new version of one lands in Brand assets: uploaded by a teammate, by a guest (a freelancer or agency), or through a file request link.
file_request.received
Files come in through a file request. When someone finishes sending files through a “Request files” link. They wait in Brand assets under “To review”.
story.answers_received
A customer answers the story questions. When a customer's contact sends their answers to "Ask the customer" (More → Customer stories).
story.approved
A customer approves a customer story. When a customer's contact submits an approval (or renews one) and approves at least one item as it stands.
story.suggestion_received
A customer suggests a change to a story. When a customer's contact suggests their own wording for items instead of approving them as they are.
story.expiring
A customer story's approval ends soon. 30 days before a customer story's approval ends, once per end date.
story.withdrawn
A customer withdraws their approval. When a customer's contact withdraws items or their whole approval; the places it's published get take-down actions.
coverage.published
Coverage goes live. When Echo's check finds a coverage link of a pitch live (Market intel → Mentions → Outreach): an article, list, profile, episode or post, with whether it names the brand and links to it. Once per link.
partner.live
A partnership goes live. When a partnership moves to Live (More → Partners and events).
event.held
An event is held. When one of the brand's own events moves to Held (More → Partners and events), with its sign-ups and attendees.
audience.objection_found
An objection isn't answered on the website. When a kept objection from Brand → Audience isn't answered on the website (at keeping it or at a refresh's check), once per objection and page. Echo adds an action to answer it.
mention.found
Someone mentions you or a competitor. When Mentions (Insights) finds a new thread, review or post that names the brand or a watched competitor, or a forum or review page AI answers cite: on Reddit, review sites, Hacker News, Stack Overflow, in Google Alerts or pasted by a teammate.
mention.negative
Someone writes negatively about you. When a new mention names the brand and Echo reads it as negative (a bad review, a complaint). Once per mention.
content.claim_wrong
Your website states a wrong figure. When the content check (FactCheck → Your website) finds a page of your website stating a price, number or result that contradicts your facts, is outdated or has no source. Once per claim.
contact.subscribed
A contact joins a newsletter list. When someone joins one of the brand's newsletter lists: through a lead form or a form on your website, the preference page, the API, a teammate or another playbook. Imports don't start playbooks. Use the list's name in a condition for a welcome sequence per list.
contact.unsubscribed
A contact unsubscribes. When someone leaves newsletter lists or unsubscribes from everything. Echo never emails them about it; use it to tell the team or update the CRM.
contact.updated
A contact's details change. When a teammate, an import or the API changes a contact's name, company, website, role or other fields. “What changed” lists the fields.
newsletter.sent
A newsletter is sent. When the last mail of a newsletter issue has gone out, with how many people got it.
framer.published
Changes go live on the Framer site. When someone in Echo publishes the brand's Framer site to staging or deploys it to production (Settings → Connections → Framer), with how many items and actions went out.
seo.rank_lost
You lose a top-3 position on Google. When a tracked keyword (Website → Health → SEO → Rankings) was in Google's top 3 last week and isn't this week. Echo adds an action to win it back. Once per keyword and week.
seo.page_broken
A page AI cites or visits breaks. When the weekly website check finds that one of your pages AI assistants cited or sent visitors to in the last 30 days now returns an error or is hidden from search (noindex). Once per page and check.
seo.score_dropped
Your Search + AI score falls. When the Search + AI score (Website → Health → SEO → Overview) falls 5 points or more from one week to the next. Echo adds an action to find out why. Once per market and week.
agent.drafted
An agent writes a draft. When one of the brand's agents (Home → Agents) finishes a draft for an action: a page refresh, a comparison page, a FAQ with schema, an answer to an objection, a pitch or llms.txt. Nothing is published or sent; a person approves it. Once per draft.
answer.wrong
AI states something wrong about you. When an AI answer (ChatGPT, Perplexity, Gemini, Claude, Google's AI Overviews …) states a price, number or fact about the brand that contradicts its fact sheet, is outdated or has no source (FactCheck). Once per prompt, assistant and day.
visibility.dropped
Your AI visibility drops. When the share of AI answers naming the brand falls 10 points or more from one run to the next (the same drop as the drop alert email). Once per market and day.
report.ready
The monthly AEO report is ready. When Echo has drafted the monthly AEO report on the 1st (Home → Results → Reports): visibility, citations, visits from AI, leads, deals and the work done, written from the numbers. Once per brand and month.
{
  "id": "evt_4GJ2kq9V…",
  "type": "form.submitted",
  "created_at": "2026-09-29T09:14:02.000Z",
  "workspace_id": "ws_…",
  "brand": {
    "id": "b_x7…",
    "name": "Fernwick",
    "domain": "fernwick.example"
  },
  "data": {
    "form": {
      "id": "sample-form",
      "name": "Newsletter"
    },
    "lead": {
      "id": "sample-lead",
      "email": "jamie@sample.example",
      "first_name": "Jamie",
      "last_name": "Rivera",
      "company": "Sample Co",
      "website": "sample.example",
      "source": "form",
      "can_email": true
    },
    "fields": {
      "email": "jamie@sample.example",
      "first_name": "Jamie"
    }
  }
}

署名付き配信

Webhookごとに固有のシークレットがあり、作成時に一度だけ表示されます。EchoはStandard Webhooks方式(webhook-id、webhook-timestamp、webhook-signatureヘッダー)で各配信に署名するため、対応ライブラリでも検証できます。配信に失敗した場合は約8時間で6回再試行します。410が返されると、そのWebhookを無効にします。

import crypto from "node:crypto";

// secret: the webhook's "whsec_…"; headers and the raw body as received.
export function fromEcho(secret, headers, body) {
  const id = headers["webhook-id"], ts = headers["webhook-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // older than 5 minutes
  const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
  const expected = "v1," + crypto.createHmac("sha256", key).update(`${id}.${ts}.${body}`).digest("base64");
  return headers["webhook-signature"].split(" ").some((s) => s.length === expected.length && crypto.timingSafeEqual(Buffer.from(s), Buffer.from(expected)));
}

Zapierとn8n

コード不要。APIキーでEchoを接続し、実行する内容を選ぶだけです。

Zapier
Triggers for every event (a new form lead, a reply, a target account signal, an action done …) and actions to add a lead, add or update an action and run a playbook. Paste an API key with the scopes you want when Zapier asks.
n8n
The Echo node (actions, leads, playbooks, metrics) and the Echo Trigger node for every event. Install n8n-nodes-echo under Settings → Community nodes, then add your API key as a credential.

APIに必要な機能がありませんか?