MentionBird
Verified verified 19 oct 2026Win the customers who ask AI what to buy.
TL;DR
MentionBird is a paid AI visibility and answer-engine optimization platform that monitors whether brands are recommended in AI-generated answers and identifies the sources influencing those recommendations. It is designed for SaaS, ecommerce, agencies, and SEO or content teams, with prompt-specific ranking advice as its main differentiator. The product is promising but has limited independent review coverage and gates broader AI-platform coverage behind higher-priced plans.
What Users Actually Pay
No user-reported pricing yet.
Our Take
MentionBird occupies a focused position in the growing AI visibility market. Instead of measuring only conventional search rankings, it tracks how brands appear when potential customers ask AI assistants which products, services, or companies to consider. This makes it particularly relevant for categories driven by comparison, recommendation, and buyer-intent questions. Its strongest feature is the connection between measurement and action. MentionBird does not merely report whether a brand was mentioned; it analyzes the sources and competitors appearing in a particular answer and proposes practical next steps. Recommendations may include improving a product page, publishing comparison content, creating video content, or pursuing coverage from a source frequently cited by AI systems. This can be more useful for small marketing teams than a generic visibility score. The main concerns are pricing, platform coverage, and measurement maturity. The Starter plan is limited to ChatGPT and Gemini, while broader platform coverage requires the more expensive Growth plan or custom pricing. Prompt runs and agent credits are separate consumption categories, which may make costs harder to forecast. There is also no free plan or standard free trial, making it harder for prospective customers to validate the data before committing. MentionBird is best suited to companies with a meaningful list of buyer-intent prompts and the marketing capacity to act on recommendations. It is less compelling for very small businesses seeking free monitoring or for teams that need content creation, outreach, or optimization work executed automatically. Because independent customer feedback is currently limited, buyers should test the product against their own prompts and compare results with competing platforms before making a long-term purchase.
Alternatives
Ranked by Revuo score — paid tiers never affect order.Ahrefs
AI Marketing Platform Powered by Big Data
SE Ranking
AI SEO Software That Gets Results
Peec AI
AI Search Analytics for Marketing Teams
OtterlyAI
AI Search Monitoring Tool: Track ChatGPT, Perplexity & Google AIO
Semrush
Data-Driven Marketing Tools to Grow Your Business
Profound
Optimize Your Brand's Visibility in AI Search
Pros
- + Prompt-specific AI Ranking Advice turns visibility data into recommended content, SEO, and digital-PR actions.
- + Source and citation analysis helps users identify the publications, pages, forums, reviews, and videos influencing AI answers.
- + Competitor tracking includes brand mentions, prominence, average position, and share of recommendations.
- + Setup is relatively low friction because the product does not require website code, plugins, DNS changes, or analytics installation.
- + Supports useful operational features such as country targeting, prompt organization, CSV import/export, recurring monitoring, and integrations with ChatGPT or Claude.
Cons
- - Independent customer-review coverage is very limited, making satisfaction, support quality, reliability, and ROI difficult to assess.
- - There is no free plan or standard free trial, although a discounted first month is advertised.
- - Broader AI-platform coverage is restricted by plan, with the entry tier covering only ChatGPT and Gemini.
- - Separate agent credits introduce additional usage limits and make the effective cost of ranking advice less predictable.
- - Unused daily prompt capacity does not roll over, and the product recommends actions but does not execute content production, publishing, outreach, or technical changes.
MCP Integrations
2 servers382 toolsSocial listening for AI agents. Search and triage every mention of your brand, competitors and topics across 16 platforms: Reddit, X, Hacker News, GitHub, Bluesky, LinkedIn, Stack Overflow, DEV, YouTube, TikTok, Instagram, news, App Store, Google Play, Trustpilot and Google Maps. Every mention is scored by AI for relevance, sentiment and intent (buying questions, complaints, bug reports). Your agent can search mentions, manage tracked keywords, read analytics and share of voice, set up Slack, Telegram, email and webhook alerts, and explore the people behind the mentions. Sign in with OAuth, no API key to paste. Prepaid pricing: $5 per keyword per month plus $0.008 per matched mention, with free credit to start. https://mentio.dev
55 tools
list_segmentsYour saved audience segments (named filters such as "Influencers" or "Switch prospects"), each with the number of people in it right now, plus presets you can save with create_segment. Pass a segment id to list_people to see its members.create_segmentSave an audience segment: a name plus a filter (platforms, tags, follower range, minimum mentions or negatives, intents seen, keyword kinds mentioned or never mentioned, first seen within N days, linkHosts they have shared a link to). Evaluated on every read, never materialized.update_segmentRename, describe or refilter a saved segment. `filter` replaces the whole filter.delete_segmentDelete a saved segment. Nobody in it is affected.list_viewsYour saved views (named filters over mentions such as "Negative about us" or "Needs a reply"). Pass a view id as viewId to search_mentions to read exactly what it selects.create_viewSave a view: a name plus a filter in the vocabulary of search_mentions (keywords or keyword kinds, platforms, status, relevant, sentiments, intents, languages, author tags, follower range, replies, link hosts, automated, free text), lists any-of, `not` lists none-of, every condition ANDed, plus anyOf for OR: groups of those conditions, at least one of which must hold. Nothing is materialized: the view selects whatever matches when it is read.update_viewRename, describe or refilter a saved view. `filter` replaces the whole filter.delete_viewDelete a saved view. No mention is affected.list_groupsThe keyword groups of the workspace, the default first: how keywords are grouped (a customer, a campaign, a product). A term may be tracked once per group; every keyword belongs to one; get_usage_breakdown by=group says what each cost. externalId finds the group carrying your own id.get_groupOne keyword group by id, with how many keywords it holds.create_groupCreate a keyword group: a name (unique per workspace), optionally your own id for it (externalId, unique too, a customer id say), and optionally its own company description (context: who the business is, what it sells, for whom), which the classifier reads in place of the whole workspace profile (guidelines and competitors included) for this group's keywords, so a rule for the group goes in that text. One group per customer with its description is how a reseller gets each customer judged as itself. Then pass its id as groupId to add_keyword.update_groupRename a keyword group, change your id for it (externalId, null clears) or its company description (context, null clears: the workspace profile applies again; new mentions are judged with it at once). The default group can be renamed but takes no description: it is the workspace itself and reads the company profile (update_company).delete_groupDelete a keyword group and EVERY keyword in it (each as delete_keyword does: its mentions go with it). The default group cannot be deleted. Says how many keywords went.search_mentionsSearch tracked mentions for your organization. Filter by keyword, platform, status (open, ignored, done), relevant, minimum relevance, minimum confidence (0 to 1), sentiment, intent, free text (q, the post text or the author name), time range (ISO 8601), one person (personId from list_people), assignee (assigneeId), author reach (minFollowers, maxFollowers), engagement the platform reported (minLikes, minReposts, minReplies, minQuotes, minViews, minBookmarks; a post without the count never passes), review stars (ratings, or notRatings to leave some out), author tags (tags, any-of), the hosts a post links to (linkHosts, any-of, a host or any subdomain of it), replies against top-level posts (isReply), whether the post reads as machine-made (automated=true for the bots, false for the rest), an alert rule's whole filter (alertId, the same mentions the rule would send), a saved view's filter (viewId, from list_views, ANDed with the rest), the kind of keyword that matched (keywordKinds: brand, competitor, topic), or the keyword's group (groupIds, or notGroupIds to leave groups out; ids from list_groups). Every filter is ANDed; for OR, anyOf takes up to 10 groups of the same conditions (an object each, all its conditions ANDed) and keeps a mention when at least one group holds, on top of the rest: anyOf=[{platforms:["reddit"],sentiments:["negative"]},{intents:["buy_intent"]}]. Snoozed mentions are hidden unless snoozed=true. sort="newest" (default) or "priority" (attention score from relevance, author reach, intent and age, over the last 30 days of matches only; each mention carries it as `priority`). Returns 10 mentions by default (limit, up to 100). Each mention nests post, author, classification and triage.get_mentionFetch a single mention by id, including its classification (relevance, sentiment, intents, confidence, uncertain, note).update_mentionThe one write on a mention: status "ignored" (not interesting) or "done" (handled), "open" to put it back; assign it to a workspace member (assigneeId, null to unassign); snooze it out of the feed until an ISO 8601 instant (snoozedUntil, null to wake it); leave an internal note (note, null to clear); or correct the classifier with `relevant` (true or false: your verdict, which sets relevance to 100 or 0 and moves the mention in or out of the relevant feed; null withdraws it) and `sentiment` (a corrected label; null restores the classifier's). Use the verdicts when the user says a mention is noise or was missed. Omitted fields are untouched. Delivery and billing never change.add_keywordStart tracking a keyword. kind is "brand" (default), "competitor" or "topic". platforms optionally restricts it to some platforms (default: every platform). New mentions containing the term will be matched, classified and delivered. For a common word, narrow it with `matching` (requiredTerms with requiredMode any|all, excludedTerms with a `*` wildcard at an end, excludedAuthors, caseSensitive): a post the rules reject is never stored or billed. `context` is one sentence the classifier reads for this keyword only ("Arc is our browser; ignore the geometry word"). `cap` ({ mentions: N }) is a monthly ceiling on its matched mentions: at the cap it stops matching until the first of the next month (UTC) or until the cap is raised, while its daily keyword charge continues. `groupId` puts it in a keyword group (list_groups; default: the workspace's default group); a term may be tracked once per group, so two groups may track the same term as two keywords. `reviewSources` collects reviews: pass each page's link (url: an App Store or Google Play app, a Trustpilot page, a Google Maps place or its maps.app.goo.gl share link) or platform (appstore|googleplay|trustpilot|googlemaps) and id; the app stores also take countries (two-letter codes, default us) and Google Play a language (default en). Every review of the page becomes a mention of this keyword, polled daily, and the last 30 days (newest 100) come in free at once. `platforms: []` makes a reviews-only keyword.update_keywordChange a keyword: the platforms it is tracked on (platforms: a list, or null for every platform), mute or unmute it, reclassify it (kind), set its classifier context (null clears), or its matching rules (matching: each field optional, an empty list clears one; requiredTerms with requiredMode any|all, excludedTerms with a `*` wildcard at an end, excludedAuthors, caseSensitive), or its monthly mention cap (cap: { mentions: N }, null removes it; a cap above this month's count resumes a capped keyword at once), or move it to another group (groupId; a 409 when that group already tracks the term), or replace where it collects reviews, App Store, Google Play, Trustpilot or Google Maps (reviewSources: the whole list, [] disconnects them; a newly added app or country brings its last 30 days free). Rules apply to new mentions only. Returns the updated keyword with its stats.get_analytics_summaryHeadline counts for a window: matched and relevant mentions, distinct posts and people, sentiment split, buying intent and questions, estimated reach (followers of the people whose count is known), and triage (open, ignored, done, waiting over 24h, handled rate, median time to done). Window: range 7d|30d|90d|365d ending today, or from/to as YYYY-MM-DD; keywordIds and platforms are lists; timezone (IANA) cuts the days, UTC by default; compare=true adds the same counts for the period right before as `previous`. Time axis is the publish date.get_analytics_seriesMentions over time: one point per day or week (bucket; default day up to 90 days) with matched, relevant and sentiment counts, as a single "total" series or split with by="platform" or by="keyword" (top 20, the rest as "other"). Same window parameters as get_analytics_summary; compare=true adds `previous`, the period right before, points aligned by index.get_analytics_breakdownOne table grouped by a dimension `by`: platform, keyword, sentiment, intent, status (open, ignored, done), hour (weekday and hour of day in timezone, for "when do people talk"), or person (who posted most, with followers). Each row has matched, relevant, share of the window in percent, a sentiment split and, with compare=true, the same group in the period right before. Same window parameters as get_analytics_summary. At most 50 groups, most matched first.get_share_of_voiceBrand against competitors: every keyword matched in the window with matched, relevant, negative and buy-intent counts and its share of brand plus competitor matches in percent (topics are counted but stay out of the split). Same window parameters as get_analytics_summary; compare=true adds the previous period's matched per keyword.get_reviews_reportThe reviews report: App Store, Google Play, Trustpilot and Google reviews the keywords collect, over a window. Totals (reviews, average stars, 1-5 distribution, replies, open 1-2 star reviews), the tags on the unhappy reviews, and one row per review page with its average stars per day or week (bucket). A review matched by two keywords counts once. Same window parameters as get_analytics_summary; compare=true adds the previous period.list_alertsList alert rules: what each watches (filter), whether it fires instantly or as an hourly, daily or weekly digest (mode, schedule), and which channels it sends to.get_alertOne alert rule by id: its filter, mode and schedule, channels and delivery stats.delete_alertDelete an alert rule. Its channels stay and can serve other rules. Irreversible; disabling it (update_alert enabled=false) keeps the rule.list_channelsList the channels alerts can be sent to: Slack channels, Telegram chats, email address lists, webhooks. Telegram chats connect from the dashboard (Settings, Integrations), not through the API.list_attentionWhat needs a person right now, newest first: a keyword whose mentions spiked in the last hour (mention.spike), whose negative share of the last 24 hours jumped (sentiment.negative_spike), that turned noisy (keyword.noisy), or a channel whose last sends all failed (channel.failing). Detected once an hour; items resolve on their own when the condition is gone. Open items by default; status "all" reads the history. Each item has a one-line title, the facts in data, and data.url pointing at the dashboard.dismiss_attentionDismiss an attention item (att_... from list_attention): it leaves the open list and does not come back while its condition lasts.create_alertCreate an alert rule. mode "instant" sends each matching mention as it happens; "hourly" sends one digest every UTC hour (five minutes past) for the previous hour, nothing when it had no mention over the floor, takes no schedule and no email channel (Slack, Telegram, webhook); "daily" sends one digest at schedule.hour in schedule.timezone; "weekly" sends one a week on schedule.weekday (0 Sunday to 6 Saturday). filter narrows by keywordIds, platforms, minRelevance (the relevance floor: absent sends relevant mentions only, 40 and up; 0 sends every scored match, noise included), minConfidence, sentiments, intents, excludeAuthors, minFollowers, tags, linkHosts (the hosts a post links to, a host or any subdomain of it). channelIds come from list_channels.update_alertChange an alert: name, enabled, mode, schedule, filter (replaces the whole filter) or channelIds (replaces the whole list).mute_authorsMute authors on an alert without touching the rest of its filter. Accepts profile or post links, @handles, u/names, Bluesky DIDs or display names; a link is stored as the author's profile. Already muted authors are skipped; an entry that names no person is rejected.unmute_authorsUnmute authors on an alert without touching the rest of its filter. Name each by the stored entry or any link to that profile or its posts; authors that are not muted are ignored.list_keywordsThe tracked keywords of your organization with their stats, poll health, matching rules and context, plus `total`. Without arguments: every keyword, newest first. Search the term and context (q), narrow by kind, status (active, muted by a person, paused by the wallet, noisy: paused by the noise brake, capped at its monthly mention cap), platform or group (groupId), order (sort) and page (limit, offset).get_keywordOne keyword by id: term, kind, platforms, matching rules, context, its monthly mention cap and whether it is at it (pausedForCap), stats (mentions, relevant, last 7 days, this month, your feedback) and poll health per platform.get_keyword_healthIs a keyword worth what it costs, and what would fix it. Over a trailing window (range 7d, 30d or 90d; default 30d): a status (healthy; noisy = 20 or more scored matches and under 30% relevant; quiet = 7 days or older with nothing relevant; capped; paused; new = under 7 days old) with reasons in plain words, matches, relevant, noise share by platform and week, what it cost, the words and authors over-represented in its noise, and suggestions. Each suggestion has a `patch`: pass it to update_keyword with the keyword id to apply it (lists hold the whole new list), and an `effect` measured by running the matcher's rules over the window's posts (noise and relevant matches it would have removed, cents saved). ai=true adds a context rewritten by a language model (cached a day; 20 model calls an hour per workspace). Read only, never billed, cached 5 minutes.delete_keywordStop tracking a keyword and delete its mentions (a post also matched by another keyword stays). Alert rules that named it stop naming it; a rule that named only this keyword is disabled rather than widened to every keyword. Irreversible; muting (update_keyword muted=true) keeps the mentions.whoamiThe workspace this credential acts on, how it authenticated (an API key or an OAuth sign-in), whether it may write, and the person behind it when there is one. Call it once at the start of a session to name the workspace and know whether write tools are available.list_membersThe people in the workspace with their role (owner, admin, member), email and user id. The user id is the value update_mention assigneeId and update_person ownerId take.get_usageThe prepaid balance (ledger, pending mention charges, effective), the daily burn and the days it buys, how many keywords run and how many the wallet paused, the matches recorded today and over 30 days, and whether tracking is stopped or the balance is low. Every matched mention bills $0.008 and every active keyword $5 a month, charged daily.get_usage_breakdownWhat the workspace consumed and was charged over a window, in USD cents at list price, grouped by ONE dimension per call: `by` = keyword (the default: days charged, mentions billed, totalCents per keyword, a deleted keyword kept with keyword.removed=true), platform, or day. `range` (7d, 30d, 90d; default 30d) reads a trailing window ending today; `month` (YYYY-MM) reads one calendar month, the shape a bill or a per-customer margin is reconciled against. Every call also returns the window's totals (keyword-days, matched and billed mentions, list-price total, what the ledger actually debited). Rows are paged (limit, offset, total). Answer "what did keyword X cost" and "where does the money go" from it; get_usage answers "how much is left". Each keyword's running-month cost is also on get_keyword as stats.cost.list_ledgerEvery movement of the prepaid balance, newest first: the welcome credit, top-ups, refunds, the daily keyword-day and mention debits, adjustments. A debit row carries the UTC day it settled and the cumulative units behind it. Cursor paged (limit up to 100). Adding funds is a checkout on the dashboard's billing page or POST /v1/billing/top-ups on the REST API.get_filtersThe workspace filters: noise rules applied to every keyword before a mention is stored (excluded terms and authors, excluded GitHub repositories, the subreddits Reddit posts may or may not come from). A post they reject is never classified, delivered or billed. Per-keyword rules live on each keyword (`matching`).update_filtersChange the workspace filters: excludedTerms (a `*` at an end is a wildcard), excludedAuthors (links, handles, names), excludedRepos (owner/name or a github.com link), subreddits.only (an allowlist; when set, excluded is ignored) and subreddits.excluded. Each list optional; an omitted list is untouched, an empty one clears it. Takes effect on new mentions within a minute.get_companyRead what the classifier knows about the company: name, description, use cases, own accounts, and the composed context it reads to judge relevance (for keywords in a group that carries its own description, the group's text replaces it; see list_groups).update_companyUpdate the company profile (name, description, useCases, accounts) or override the classifier context directly. Profile edits recompose the context; an explicit context wins until the next profile edit. The context is the single biggest lever on relevance scoring, so keep it accurate and specific; it does not reach keywords in a group with its own description (update_group for those). Omitted fields are untouched.list_peopleThe people who wrote mentions matching your keywords: name, profile, platform, how many of their posts matched (and how many scored relevant), their sentiment split, when they were first and last seen, and where your outreach stands (owner, stage, last contacted). Filter by platform or name, find one person by handle or profile link (handle), outreach stage (stages), owner (ownerIds, "none" for unowned) or automated (bot accounts, whose posts mostly read machine-made); sort by mentions or recency. Use search_mentions with authorId to read what one person said. Email addresses are not returned over MCP: profile.email is always null (the dashboard and the REST API show it where the person published it).get_personOne person from the audience, with their counts, tags, notes and mute for your organization, their outreach (owner, stage, last contacted), plus their public profile (bio, company, location, website and linked accounts) where the platform lists it. GitHub authors are looked up today; profile is null until then. Email addresses are not returned over MCP: profile.email is always null (the dashboard and the REST API show it where the person published it).update_personAnnotate a person for your organization: replace their tags, set notes, mute/unmute them, or set the outreach owner (ownerId, a member user id; null clears) and stage. Muting hides their posts from the feed and from every channel; ingest and billing are unchanged.merge_peopleDeclare that two accounts are the same person, for your organization only: fold account `id` into person `into`. Their mentions, tags and notes combine; the folded account shows under the person's platforms.split_personUndo a merge: the account becomes its own person again for your organization.list_activitiesThe outreach log on one person, newest first: every logged contact with who reached out, the channel (email, x, linkedin, bluesky, reddit, github, call, meeting, other), when, and a short note. Check it, and the person's outreach owner, before reaching out so two teammates never contact the same person without knowing.log_activityRecord that someone reached out to a person: an email, a DM, a call. The first contact claims an unowned person for whoever reached out and moves not_contacted to contacted; an existing owner and a later stage are kept (set them with update_person). memberId defaults to the signed-in user; with an API key and no memberId the activity is unattributed and claims nobody. Returns the activity and the person as they now read.delete_activityDelete an outreach activity logged by mistake. The person's owner and stage stay as they are.get_mention_statsMention counts for the last N days (default 7), grouped by platform and by sentiment, optionally filtered to one platform or keyword. Unclassified mentions appear under sentiment "unclassified".
Send and receive across email, SMS, WhatsApp, and voice. One API, one contract.
328 tools
api_keys_createCreate a workspace key and receive its token once, in this response; no later call reads it back. Scopes are limited to the data plane, so a key can never issue or revoke another one. Expiry is fixed at creation, and `cidrs` is applied in the same transaction, so an invalid range fails the whole call instead of leaving the key unrestricted.audiences_add_contactsAdd up to 1,000 existing contacts to a static audience by ID. Fails entirely if any contact ID does not exist. To add contacts you have not created yet, use `contacts_batch` with `audience_ids` instead: it matches or creates each contact by email address and assigns it to the audience in one call.audiences_createCreate an audience in the workspace. New audiences start empty; add contacts with `audiences_add_contacts` or `contacts_batch`. Only static audiences can be created today.audiences_deleteDelete an audience and its memberships; contacts themselves are not deleted. Fails while a broadcast targeting the audience is scheduled, accepted, sending, or canceling.audiences_getGet a single audience by ID: name, description, and type. Members are listed separately with `audiences_list_contacts`.audiences_listList the workspace's audiences as a cursor page, newest first. Filter by name substring with `q`.audiences_list_contactsList the contacts in a static audience by ID, as a cursor page ordered by when each contact joined (most recent first). Each entry pairs the contact with its join time.audiences_remove_contactRemove one contact's membership from an audience. The contact itself is not deleted and stays a member of any other audiences.audiences_remove_contactsRemove up to 1,000 contacts from a static audience by ID. Fails entirely if any contact ID does not exist; contacts are not deleted.audiences_updateUpdate an audience's name or description. Omitted fields are unchanged; a `null` description clears it.billing_plans_getRead a billing plan by ID, including its tier, list price, entitlements, and resource quotas. This operation requires no authentication.billing_plans_listList active billing plans with their tiers, list prices, entitlements, and resource quotas. This operation requires no authentication.compliance_identities_listList the businesses this workspace has stored as compliance parties, so a registration can name the one it is for. Returns one page, newest first; follow `next_cursor` as `starting_after` for the rest.compliance_requirementsWhat one country asks for before it will approve one registration, with where each item stands and why any was refused. `sms_senders_requirements` says which countries want a registration; this says what one is asking for, addressed by that row's `registration_id` as `subject_id`. Without `subject_id` it answers the form with no submission behind it, every item unanswered except those `identity_id` prefills, and `program` turns required, because a country can run more than one and there is no registration to read it from. `satisfied` is whether every required item is approved or not applicable; `needs_input` separates items still waiting on you from answers already with a reviewer.compliance_submissions_createFiles a country's registration answers, all of them in one call, and there is no draft to build up first. What to send is `compliance_requirements`'s `fields`, item by item; a country it does not cover is refused rather than accepted empty. Filing twice for the same registration returns 409, so correct a refused answer with `compliance_submissions_resupply` instead. The answers are a legal representation about the business, relayed onward to a carrier or a regulator under the name of the business they describe, so confirm them with the user before this call rather than filing on your own.compliance_submissions_resupplyReplaces the answers a reviewer refused, that expired, or that were never supplied, on a registration already filed. Which ones, and why each was refused, is on the item in `compliance_requirements`'s `fields`; anything already accepted is left alone and does not need sending again. Correcting a refused answer is the same legal representation as making it, filed under the same business's name, so confirm the replacements with the user before this call rather than filing on your own.contact_properties_archiveArchive a contact property: the key is rejected in new contact writes and stops rendering in templates, while stored values remain readable. The key stays reserved and counts toward the 200-property limit; reverse with `contact_properties_unarchive`.contact_properties_createDefine a custom contact property (key + value type) that becomes available in contact data and as a broadcast template variable. The key and type cannot change after creation; a workspace holds at most 200 properties, archived included.contact_properties_getGet a single contact property by ID: key, type, fallback value, and archived state.contact_properties_listList the workspace's contact properties as a cursor page, newest first. Archived properties are included, marked by their archived flag.contact_properties_unarchiveReactivate an archived contact property so its key is accepted in contact writes and renders in templates again. Fails with a conflict if the property is not archived.contact_properties_updateUpdate a contact property's fallback value. Only the fallback value can change; the key and type are fixed at creation, so a different key or type needs a new property.contacts_batchCreate or update up to 1,000 contacts in one request. Match each entry against every supplied identifier (`email`, `phone_number`, and `external_id`), or set `match_on` to use one identifier. Optionally add all successful contacts to up to 10 audiences. Results follow submission order.contacts_createCreate a contact identified by an email address, an E.164 phone number, or both. Fails with a conflict if the email, phone_number, or external_id is already used by another contact. For bulk import or create-or-update semantics use `contacts_batch`.contacts_deleteDelete a contact and remove it from every audience it belongs to. Suppression records for the address are unaffected.contacts_getGet a single contact by ID. Look up an ID by exact email, phone_number, or external_id with `contacts_list`.contacts_listList the workspace's contacts as a cursor page, newest first. Look one up by exact email, phone_number, or external_id, repeating phone_number to resolve up to 50 numbers in one call (raise limit to match), or search by email, name, or phone substring. Pass include_total for a total count.contacts_updateUpdate a contact's name, `external_id`, email, `phone_number`, or custom data. Only supplied fields change; custom data keys are merged, with `null` removing a key. A contact keeps at least one identifier: clearing both email and `phone_number` is rejected.docs_readFetch the full Markdown of one documentation page by the `slug` from a documentation search result. The response URL is the page's citable source. Use `index` for the documentation landing page. This operation requires no authentication.docs_searchSearch the documentation by keyword and return ranked sections with deep links, page slugs, and matching snippets. Use `docs_read` with a result's `slug` to fetch the full page. Set `contents` to `highlights` to include matching passages. This operation requires no authentication.email_broadcasts_cancelCancel a scheduled, accepted, or sending broadcast. This stops every delivery that has not gone out yet. Recipients already dispatched are not recalled. Calling this again on a broadcast already canceling or canceled returns its current state rather than an error. A draft cannot be canceled, because it was never sent. Delete it with `email_broadcasts_delete` instead.email_broadcasts_countsPreview how many contacts a broadcast can reach before sending. The `total` value includes every contact in the audience. The `addressable` value counts contacts with an email address. The `sendable` value counts contacts that are not suppressed for the broadcast's category and can receive the broadcast. These describe the audience, not delivery, and sending does not change them: to find out what happened to a broadcast that has sent, read its recipients or its events. The broadcast must already have an audience selected.email_broadcasts_createCreate a broadcast that sends one piece of template content to a stored audience. Leave `send` as `false` (the default) to save an editable draft. Update it with `email_broadcasts_update` and send it later with `email_broadcasts_send`. Set `send` to `true`, optionally with `scheduled_at`, to send it in this call. A send needs a verified `from` address, an `audience_id`, and a `template`.email_broadcasts_deletePermanently delete a draft broadcast. Only a draft can be deleted. To stop a scheduled or sending broadcast, use `email_broadcasts_cancel` instead.email_broadcasts_getFetch one broadcast by its `broadcast_id`, with its audience reference and counters. For the full recipient list use `email_broadcasts_list_recipients`, and for the delivery timeline use `email_broadcasts_list_events`.email_broadcasts_listList broadcasts in the workspace, newest first. Filter by lifecycle `status`, `audience_id`, or `tag`, search tag names/values with `q`, or narrow to a window with `created_after`/`created_before`. Use `email_broadcasts_get` for full detail on one broadcast.email_broadcasts_list_clicked_linksList the destination URLs a broadcast's recipients clicked, each with its exact click count, distinct-recipient count, and the link's own name (when the message named it). Grouped over every click event the broadcast has, not a sample; `data` is capped at the 100 most-clicked URLs and `total` is the uncapped count of distinct URLs clicked.email_broadcasts_list_eventsList the per-recipient delivery timeline for a broadcast (sends, opens, clicks, bounces, and so on), paginated. Filter by `type` (for example `email.bounced`, `email.opened`).email_broadcasts_list_recipientsList the recipients resolved for a broadcast with their per-recipient delivery state, paginated. It shows who a broadcast reached and how far each one got. The list is empty until the broadcast starts sending. Pass `to` to look up one address instead of paging the whole set.email_broadcasts_sendSend a draft or scheduled broadcast, either immediately or at `scheduled_at`. Calling this on a broadcast that already has a schedule reschedules it instead of sending a duplicate. Calling it on an `accepted` broadcast retries dispatch. Once the broadcast has started sending or reached a final state, calling this again returns a conflict error.email_broadcasts_updateUpdate a draft or scheduled broadcast. Only the fields you supply change. The rest stay as they are. Once the broadcast is accepted for sending, editing returns a conflict error. Use `email_broadcasts_cancel` to stop a broadcast that is already sending.email_cancelCancel a scheduled email before it sends. Only works while the message's `status` is still `scheduled`. Once it starts sending, or was already canceled, the call returns a conflict error. Canceling does not return consumed scheduled-send quota.email_contentRead the stored HTML and text bodies of a sent message. Content exists only if the message had content storage enabled, and only for 30 days after sending. A `404` means nothing was stored. A `425` means the content is still being stored, and the call can be retried. A `410` means it has expired.email_dedicated_ips_assignMove a dedicated IP into the IP pool given by ip_pool_id. An IP is always in exactly one pool, so this is a move. The last IP cannot leave the default pool, and the shared pool cannot hold dedicated IPs.email_dedicated_ips_createPurchase one or more dedicated IPs into an IP pool. The first purchase creates a dedicated pool automatically; later purchases require `ip_pool_id`. This paid organization-level action can require a wallet top-up.email_dedicated_ips_deleteCancel a dedicated IP subscription by id. The IP stays usable until the end of the billing period. The last IP in the default pool cannot be canceled. Destructive and billing-affecting.email_dedicated_ips_getFetch one dedicated IP by ID with its current status, warmup progress, and pool assignment. This operation is read-only.email_dedicated_ips_listList the dedicated IPs available to the workspace as a cursor page, each with its status, warmup progress, and pool assignment. Read-only view shared across the organization. Purchase and manage IPs through the organization endpoints.email_domains_createRegister a new sending domain and get the DNS records to publish. Flow: call this, publish the returned DNS records at your DNS provider, then call email_domains_verify (repeat until status is verified — DNS propagation can take minutes to hours).email_domains_deleteDelete a sending domain by ID. Revokes its sender authorization: new sends from the domain are rejected afterward, while historical statistics and events for past sends are preserved. Destructive.email_domains_getFetch one sending domain: verification status and the DNS records with their individual verification states.email_domains_listList the workspace's sending domains with their verification status, as a cursor page.email_domains_updateUpdate a sending domain's tracking and inbound configuration. Tracking: click_tracking and open_tracking apply immediately to new sends, and the tracking domain can be set, changed, or removed (the name part only, and the sending domain is appended for you). Enabling either toggle with no tracking domain configured returns 409, and removing the tracking domain while either toggle is still on also returns 409. Tracking-domain changes on a verified domain are staged behind DNS verification, so the current config keeps serving until the new records verify. Inbound receiving: inbound.enabled starts or stops receiving mail for the domain. Enabling requires the domain's DKIM to be verified first (a fresh enable on an unverified domain returns 422), and a domain already receiving inbound for another organization returns 422. The MX records to publish are always listed in dns_records regardless, marked optional until inbound.enabled is set, so receiving starts only once you set it even when those records are already published. Publishing them earlier is not free: on a domain at the zone apex they replace the MX records carrying its existing mail, changing where that mail is delivered.email_domains_verifyTrigger a DNS verification check for a sending domain and return the refreshed domain with per-record results. Safe to repeat while waiting for DNS propagation.email_getFetch one email message by id — aggregate delivery status, per-recipient delivery states, and the event timeline (queued → processed → delivered, opens/clicks, or bounces with reason). High-volume emails return the first page of events; more are available via events_next_cursor. The message body (html, text) is not returned.email_inbound_addresses_createCreate a new inbound address you can forward a real mailbox to. The response includes the address to forward that mailbox to.email_inbound_addresses_deleteDelete an inbound address. Mail forwarded to it afterward is no longer received.email_inbound_addresses_getFetch one inbound address by its ID: the address you forward mail to, plus its label. Use `email_inbound_addresses_list` to find IDs.email_inbound_addresses_listList the workspace's inbound addresses as a cursor page.email_inbound_addresses_updateUpdate the label on an inbound address.email_inbound_messages_attachmentDownload one attachment's raw bytes from a received email. The attachment ID comes from the manifest `email_inbound_messages_attachments` returns. The response is raw bytes; a received message and its attachments together are capped at 25 MB.email_inbound_messages_attachmentsList attachment metadata for a received email. Fetch each attachment's bytes with `email_inbound_messages_attachment`.email_inbound_messages_bodyFetch a received email's parsed, decoded body: `html` and `text`, each `null` when the message had no such part. For the original bytes use `email_inbound_messages_raw`.email_inbound_messages_getFetch one received email's parsed metadata: addresses, subject, threading headers, authentication results, and the attachment manifest. Use `email_inbound_messages_body` for the body, `email_inbound_messages_raw` for the original MIME, and `email_inbound_messages_attachment` for attachment bytes.email_inbound_messages_listList received (inbound) emails as a cursor page, newest first. Filter by sender, inbound address, or received time.email_inbound_messages_rawDownload a received email's original RFC 5322 (MIME) bytes. The response is the undecoded message rather than the parsed fields the get and body operations return. A received message, including its attachments, is capped at 25 MB.email_ip_pools_createCreate an IP pool that belongs to the organization. The pool is available immediately.email_ip_pools_deleteDelete an IP pool by ID. Only empty pools can be deleted, so move or cancel its dedicated IPs first. The default pool and the shared pool cannot be deleted.email_ip_pools_getFetch one IP pool by id with its assigned dedicated IPs. Use the reserved id `ipp_shared` for the shared pool. Read-only view.email_ip_pools_listList the IP pools available to the workspace as a cursor page. Pools group dedicated IPs for sending; the result is shared across the organization. Read-only view.email_ip_pools_updateRename an IP pool or make it the organization default. Setting `is_default` to `true` moves the default to this pool; setting it to `false` on the current default is rejected. Pass `ipp_shared` to restore the shared default.email_listList sent email messages, newest first, as a cursor page ({data, next_cursor, …}). Pass next_cursor back as starting_after to fetch the next page.email_mailboxes_composeSend a new email from this mailbox's own address, starting a new conversation. Replies to it thread back automatically. To reply within an existing conversation, use the reply endpoint on one of its messages.email_mailboxes_createCreate a mailbox: a durable agent identity that owns an email address, groups mail into conversations, and remembers conversations for its retention tier.email_mailboxes_deleteDelete a mailbox. The address stops receiving immediately and is quarantined. The mailbox and its remembered messages stay restorable for 30 days through the restore endpoint, then are permanently deleted.email_mailboxes_getRead one mailbox by ID. A mailbox deleted within its 30-day restore window is still returned, with `deleted_at` set. Once that window closes it is gone and this returns `404`.email_mailboxes_labelsList the labels available in a mailbox: the built-in system labels (inbox, archive, spam, blocked, sent, trash, unread) plus every custom label in use.email_mailboxes_listList the workspace's mailboxes as a cursor page, newest first. Search addresses and display names with q, or filter by exact address, state, or domain.email_mailboxes_receive_rules_createAdd an allow or block rule for a sender address or domain to a mailbox. Block always wins. Up to 200 rules per mailbox.email_mailboxes_receive_rules_deleteRemove a receive rule from a mailbox. Rules have no update operation, so a rule's allow or block action cannot be changed after it is created.email_mailboxes_receive_rules_listList a mailbox's allow/block receive rules as a cursor page, oldest first. Filter by action.email_mailboxes_restoreRestore a mailbox deleted less than 30 days ago: the address starts receiving again and the remembered messages are back. Past the window the mailbox is permanently deleted and returns `404`. A mailbox that is not deleted returns `409`.email_mailboxes_resumeResume a suspended mailbox so it can send and receive again and its conversations become visible. Fails if your plan does not have room for another active mailbox (or another custom inbox.ai handle). Delete an active mailbox or upgrade first. A mailbox that is not suspended returns `409`.email_mailboxes_statsRead a mailbox's sent and received email statistics over a window: a period summary plus a bucketed series. Rows are bucketed by event time rather than send time, so engagement that arrived during the period for messages sent earlier is counted here. Both window bounds must use the same form, calendar days or RFC 3339 instants, matching the granularity.email_mailboxes_updateUpdate a mailbox's display name, reply-to, receive policy, retention tier, IP pool, or metadata. Lowering the retention tier requires `confirm=true` when it would delete remembered messages older than the new cutoff.email_recipientsList a message's per-recipient delivery state as a cursor page: each `to`/`cc`/`bcc` address with its role, current `status`, bounce or rejection detail, and open and click counts. This is how you find which specific addresses failed when the message's own `status` is mixed, such as `partial_failure`.email_sendSend one email. Supply inline content (`subject` plus `html`/`text`), or send a stored `template` by its `id` or name with its `parameters`. The response is the queued message with its `id`. Delivery is asynchronous, so use `email_get` to check delivery status and events.email_send_batchSend up to 100 emails in one call. All items are validated before any are queued, so one invalid item rejects the whole batch instead of a partial success. The response has one entry per message, in submission order, each with its own `id`. Items cannot set `scheduled_at`; use `email_send` for a scheduled single message. Attachments are supported on individual messages, subject to both the per-message generated-size cap and the hard batch request-body cap.email_stats_by_bounce_codeBounce counts grouped by the SMTP error code the receiving mail server returned. Each row also breaks the bounce down into its hard, soft, admin, block, and undetermined split. It omits delivered, open, and click counts because a bounce code only appears on a bounce event. For bounces broken down by destination instead, use `email_stats_by_recipient_domain` or `email_stats_by_mailbox_provider`.email_stats_by_broadcastEmail delivery and engagement stats grouped by broadcast. Only broadcast sends appear. Reflects roughly the last 30 days of activity.email_stats_by_categoryEmail delivery and engagement stats grouped by category, meaning `transactional` compared with `marketing`. Rows are ranked by `sort`, `processed` by default. Set `include_trend=true` to add a per-bucket rate series to each row.email_stats_by_clientOpens and clicks grouped by mail client, operating system, or device type, whichever you choose with `group_by`. It only has engagement counts, no delivery counts or rates. For engagement grouped by geography instead, use `email_stats_by_location`.email_stats_by_complaint_typeSpam-complaint counts grouped by the feedback-loop complaint type, for example `abuse`, `fraud`, or `virus`. This complaint-only breakdown omits delivery and engagement counts. For complaints broken down by destination instead, use `email_stats_by_mailbox_provider` or `email_stats_by_recipient_domain`.email_stats_by_locationOpens and clicks grouped by country, region, or city, whichever you choose with `group_by`. It only has engagement counts, no delivery counts or rates. For engagement grouped by mail client or device instead, use `email_stats_by_client`.email_stats_by_mailbox_providerEmail delivery and engagement stats grouped by recipient mailbox provider, for example `gmail`, `microsoft`, or `yahoo`. It covers the delivery stage onward and omits accepted or processed counts. For a per-region split within a provider, use `email_stats_by_mailbox_provider_region`; for exact destination domains instead, use `email_stats_by_recipient_domain`.email_stats_by_mailbox_provider_regionEmail delivery and engagement stats grouped by a mailbox provider and provider region pair, for example `gmail` in `NA`. It covers the delivery stage onward and omits accepted or processed counts. For the provider-level view without the region split, use `email_stats_by_mailbox_provider`.email_stats_by_recipient_domainEmail delivery and engagement stats grouped by exact recipient mailbox domain, for example `gmail.com`. Finer-grained than `email_stats_by_mailbox_provider`, which buckets domains into providers.email_stats_by_sending_domainEmail delivery and engagement stats grouped by sending (`From`) domain, so you can compare deliverability across your workspace's verified domains. For per-IP reputation instead, use `email_stats_by_sending_ip`.email_stats_by_sending_ipDelivery and bounce stats grouped by sending IP, with deferral counts alongside them. `sort=bounces.block` surfaces reputation-damaged IPs first. Engagement, accepted, and processed counts aren't available per IP, and complaint and out-of-band bounce counts always read `0` here. For workspace-wide figures, use `email_stats_daily`.email_stats_by_tagEmail delivery and engagement stats grouped by tag, one row per `name:value` pair set at send time. Rows are ranked by `sort`, `processed` by default. Set `include_trend=true` to add a per-bucket rate series to each row.email_stats_by_templateEmail delivery and engagement stats grouped by the template used at send time, keyed by template id (`emt_…`); only templated sends appear. A single template's trend over time comes from `email_stats_daily` with its `template` filter.email_stats_dailyPer-day email stats series (counts, rates, latency percentiles), gap-filled with zero rows, max 365 days. At most one filter of `category`, `sending_domain`, `tag`, `sending_ip`, `recipient_domain`, `template`. For hour resolution use `email_stats_hourly`; for one aggregate row use `email_stats_summary`.email_stats_hourlyPer-hour email stats series, gap-filled with zero rows, max 720 hours (30 days). Takes the same single-dimension filters as `email_stats_daily`; for longer ranges use `email_stats_daily`, for one aggregate row use `email_stats_summary`.email_stats_summaryAggregate email KPIs for one period: sends, delivered, bounces, complaints, opens, clicks, their rates, and latency percentiles. The `from` and `to` values are both `YYYY-MM-DD` days or both RFC 3339 instants (hour grain). Add `compare=previous_period` for deltas versus the prior window. For a per-day or per-hour series use `email_stats_daily` or `email_stats_hourly`.email_suppressions_addAdd an email address to the workspace suppression list to stop delivery to it.email_suppressions_checkCheck whether one email address is suppressed before sending to it. Returns suppressed=true with the matching suppression records (id, reason) when it is.email_suppressions_listList the workspace's email suppressions, which block delivery to an address, as a cursor page.email_suppressions_removeRemove one suppression record by ID, re-enabling delivery to that address. Destructive: the suppression usually exists because the address bounced or complained. Removing it without a reason damages sender reputation. A `complaint` record cannot be removed this way; remove it from the dashboard instead.email_templates_createCreate a template and its first editable draft, optionally with per-language content. The display name defaults to `slug`, and a used slug returns a conflict. Submit the draft before sending it.email_templates_deleteDelete a template and every version it holds, freeing its slug for reuse in the workspace. The deletion cannot be undone, and a later send naming the template is rejected. A template a broadcast still references cannot be deleted until that broadcast finishes sending, and returns a conflict.email_templates_duplicateCopy a workspace or built-in `system` template into a new unpublished template. Its editable draft inherits the source's current content, category, authoring format, and description. Supply `slug` or use the derived `-copy` slug. A slug already in use returns a conflict.email_templates_getRead one template's metadata: the state of every language it has, the languages it can send today, the draft revision, and its draft and published version IDs. The response omits content; read a version's language to retrieve it. Accepts a workspace template ID (`emt_…`) or a built-in `system` template's `bird_` slug.email_templates_listList email templates as a cursor page. The list covers both the workspace's own templates and our built-in `system` templates. Filter to one tier with `scope`, and filter further by category, source, theme, or a search across slug, name, and description. A theme narrows the built-in catalog to one of its five visual themes, so naming one returns built-ins alone.email_templates_previewRender a template with sample values and return the resulting subject, HTML, and plain-text bodies: the personalized email as it will send. Renders the draft by default. Pass `version` to select a published version instead; built-in `system` templates have no versions, so `version` on one returns a validation error. Pass `contact` to fill the personalization from a real contact's record. Sample `parameters` cap at 16 KB serialized. Personalization that is invalid or unsupported returns a validation error naming what to fix.email_templates_updateChange a template's metadata and draft settings without editing its content. Save content on the draft version. Pass the last-read draft `revision`; a concurrent edit returns a conflict.email_templates_versions_deleteThrow away the draft's unsaved changes, resetting its content to what is currently published.email_templates_versions_getRead one version of a template: its lifecycle metadata (`status`, `version_number`, `published_at`), the content it froze in every language, and the `variables` that content expects at send time.email_templates_versions_languages_deleteRemove one language from a template's draft. The current default cannot be removed on its own; update the template to point the default at a different language first, then remove the old one.email_templates_versions_languages_getRead one language's subject and bodies from a template version.email_templates_versions_languages_listList the languages a template version holds, with each language's revision and fingerprint but not its content.email_templates_versions_languages_setSave one language's full content on a template's draft, creating the language if the draft does not have it yet.email_templates_versions_languages_updateChange some fields of one language on a template's draft, leaving the rest as they are.email_templates_versions_listList every version of a template (the draft plus all published versions), newest first.email_templates_versions_rollbackMake an earlier published version live again and reset the draft to its content, so editing continues from it. The change is immediate, creates no new version, and leaves version history unchanged. The request must include the draft `revision` last read. The draft's current content is replaced. Only published versions can be rolled back to.email_templates_versions_submitFreeze a complete draft as the new immutable live version. Every language needs a subject and body, and the default language must be present. Submission is all or nothing and reports every language error. Set `validate_only: true` to check without publishing, or pass `expected_revision` to reject a concurrent edit. An unchanged draft is rejected.email_threads_deleteMove a conversation and all its messages to trash (purged after 30 days), or delete permanently with `?permanent=true`.email_threads_getGet one conversation: participants, counts, labels, read state. Fetch its messages with the thread messages endpoint.email_threads_listList mailbox conversations as a cursor page, most recently active first. `label` selects the view: inbox (default), archive, spam, blocked, or a custom label. Filter by mailbox, contact, participant address, or subject substring.email_threads_messages_attachmentDownload one attachment's raw bytes from a conversation message (inbound or outbound). Available for 30 days after the message occurred.email_threads_messages_attachmentsList the attachments on a conversation message. Bytes are downloadable for 30 days, and the metadata stays readable afterward on the message's attachment_manifest.email_threads_messages_bodyGet the original rendered HTML and plain-text body of a conversation message. Available for 30 days. After that, use the message's extracted_text.email_threads_messages_getGet one conversation message with its extracted plain text, readable for the mailbox's full retention tier without MIME parsing.email_threads_messages_listList the messages in a conversation newest first, both directions. Page older messages with `starting_after`, and pass `include=extracted_text` to inline each message's extracted plain text.email_threads_messages_rawGet the original RFC 5322 (MIME) content of a received conversation message. Available for 30 days.email_threads_messages_replyReply to a specific conversation message from the mailbox's own address. To reply to a conversation, target its newest received message. Recipients, subject, and threading headers are derived automatically.email_threads_updateAdd or remove labels on a conversation, or link and unlink a contact. Adding `spam` files it as spam, `archive` clears it out of the inbox, and `inbox` brings it back.email_tools_analyze_dmarc_reportAnalyze a DMARC aggregate report supplied as `report_xml`. Returns totals, per-source-IP SPF and DKIM alignment results, and actionable findings. The analysis is offline and sends no message.email_tools_analyze_headersAnalyze a raw email's headers for headline fields, SPF/DKIM/DMARC verdicts, and the relay path with per-hop delays. Content after the first blank line is ignored. The analysis is offline and sends no message.email_tools_auditResolve and validate a domain's live DMARC, SPF, DKIM, BIMI, and MX records, including alignment and SPF lookup-limit checks. Returns severity-tagged findings and recommendations. DKIM needs a `selector`, which DNS cannot discover; the audit performs DNS lookups but sends no message.email_tools_split_dns_recordSplit a DNS TXT `value` into quoted chunks of at most 255 octets. Returns the raw chunks and a ready-to-publish, quoted, space-joined string without performing a DNS lookup.email_tools_validate_bimiValidate and parse a BIMI TXT `record`. Returns the logo and certificate URIs with errors and warnings, including non-HTTPS URIs or a missing certificate. Parsing is offline and performs no DNS lookup.email_tools_validate_dmarcValidate and parse a DMARC TXT `record`. Returns the resolved policy with errors and warnings, including a missing `p`, an invalid percentage, or no aggregate-report address. Parsing is offline and performs no DNS lookup.invitations_createInvite an address to this workspace. If it matches an organization member who is not in this workspace yet, they are added directly. The response returns a member instead of an invitation, and the type discriminator identifies the result.invitations_getRead one workspace invitation, including its current status and when it expires.invitations_listList the workspace's invitations as a page. Only pending ones come back unless you pass a status filter.invitations_revokeCancel a pending workspace invitation. The link stops working immediately and the invitee can no longer use it to join.lookup_emailCreate a deliverability lookup for one email address. Returns `result`, `delivery_confidence`, address `flags`, an undeliverable `reason`, and `did_you_mean` when a correction is available. Treat unknown `result` and `reason` values as valid additions and use `delivery_confidence` as the fallback; each completed lookup incurs the same charge.lookup_phone_numberCreate a lookup for a phone number's networks, porting state, country, and line type. Pass `type` to request separately billed `classification`, `porting`, `presence`, `roaming`, `sim_swap`, or `score` blocks. Each block reports its own status, and only blocks with an `ok` status add a charge; the lookup does not contact the number.members_createAdd an existing organization member to this workspace by user id, with a workspace role. Organization membership is the precondition: a user who does not have it yet reaches a workspace only through `invitations_create`.members_deleteRemove a user's role grant in this workspace. They remain a member of the organization.members_listList the users holding an explicit role grant in this workspace, newest grant first, as a page.members_updateChange a user's workspace role. They must already be a member of this workspace.numbers_available_getRe-checks one number from `numbers_available_list` against the carrier, so a stale search result is caught before it is ordered.numbers_available_listSearches one country's numbers on sale. Our own inventory answers first and pages; the last page can carry a live carrier snapshot, so a number seen here may be gone by the time it is ordered.numbers_getReads one allocated number by the id `numbers_list` returns. Carries its status and, where a country demands ownership paperwork, what is still outstanding on it.numbers_listPages the numbers allocated to the workspace, dedicated and shared alike. Narrows on country, type, prefix and capability, so one number is reached without walking every page.numbers_orders_createBuys a number and starts its monthly charge. Most orders settle inline; one waiting on a carrier comes back pending and is followed with `numbers_orders_get`. A setup fee already taken is not refunded if the order then fails.numbers_orders_getReads one order's current state, and the number it produced once completed. This is the poll for an order that came back pending.numbers_orders_listPages the workspace's purchase attempts, newest first, filtered by status. An order outlives its attempt, so a failure stays readable with the reason it carried.numbers_releaseGives a dedicated number back and stops its monthly charge. Irreversible: the number leaves the workspace and the channels built on it stop sending. A shared number cannot be released.organization_invitations_createInvite an address to the organization with an organization role, workspace roles, or both. At least one of the two must be supplied.organization_invitations_getRead one organization invitation, including its current status and when it expires.organization_invitations_listList the organization's invitations. Only pending ones come back unless you pass a status filter.organization_invitations_revokeCancel a pending organization invitation. The link stops working immediately and the invitee can no longer use it to join. Returns a conflict if the invitation is not pending.organization_members_deleteRemove a member's organization role and all workspace roles at once. Rejects removing yourself from the organization and removing the organization's last owner.organization_members_getRead one organization member: their organization role and every workspace role they hold.organization_members_listList everyone holding any grant in the organization, whether an organization role or only a workspace role.organization_members_updateChange a member's organization-level role, or pass `org_role: null` to remove it while keeping their workspace roles. Rejects changes to your own role, removing the organization's last owner, and removing a role that would leave the member with no workspace access.organization_workspaces_createCreate a workspace in the caller's organization. Requires organization-level write access.organization_workspaces_deleteDelete a workspace. Access ends at once, with the workspace hidden and its API keys revoked, while its data and configuration are held for 7 days and can be restored through support, then purged. Fails with a conflict if it is the organization's only workspace.organization_workspaces_getRead any workspace in the organization by ID, including one where the caller holds no workspace-level role.organization_workspaces_listList the organization's workspaces as a page, newest first.organization_workspaces_updateUpdate mutable fields on any workspace in the organization, including one the caller holds no workspace-level access to.realtime_apps_createProvision a Realtime app and its first key. `region` is immutable once set and must be one of `realtime_regions_list`. The response is the only place the key's secret ever appears, and no operation can read it back: recovering from a lost secret means creating another key. An app is what the publish and channel-inspection operations address.realtime_apps_deletePermanently delete a Realtime app. Every connected client is disconnected, all keys and configuration are removed, and clients holding one of its keys start failing immediately. Deleted apps cannot be restored.realtime_apps_getRead one Realtime app's configuration and the connection details a client needs (`app_id`, `region`). Key material is never included, so a client that also needs a key uses `realtime_apps_keys_list`.realtime_apps_keys_createAdd a key to an app and read its secret. Takes no body. This response is the only place the secret appears, so a caller that does not capture it has to create another key. The app's existing keys keep working, which is what makes this the first step of a rotation: add, roll out, then revoke the old key.realtime_apps_keys_listList an app's keys, oldest first, without their secrets: a secret is readable only in the response that created it. Revoked keys are excluded unless `include_revoked` is true. An app can hold several live keys at once, which is what makes rotation zero-downtime.realtime_apps_keys_revokeRevoke a key. It stops working immediately and every client still holding it fails, so revoke only after the replacement is rolled out. The record survives with `revoked_at` set rather than disappearing. Revoking a key twice is a conflict, and an app's last remaining key cannot be revoked at all.realtime_apps_listList the workspace's Realtime apps as a cursor page, filterable by a case-insensitive `name` substring. Each entry carries the connection details a client needs (`app_id`, `region`) but no key material.realtime_apps_updateRename a Realtime app or change its configuration flags. Omitted fields keep their current value. Region cannot be changed after creation, so moving an app to another region means creating a new one and repointing clients.realtime_regions_listList the regions a Realtime app can be created in. Read this before creating an app: `region` is immutable, and the identifiers here are the only accepted values.request_logs_getRead one request log entry with the captured request and response bodies that list responses omit, sensitive fields redacted and oversized values truncated. Entries live for one day, so a not-found response means the ID is unknown or already expired.request_logs_histogramRead five-minute request and error counts for a window, to plot above the request log. Empty buckets are omitted, the window defaults to the last 24 hours, and anything wider is clamped to 24 hours, which is the retention limit.sms_10dlc_brands_createRegister a 10DLC brand with the business identity details US carriers require. The brand starts pending while the registry reviews it; only once it is approved can you register a campaign under it. If the registry rejects it, correct the details and resubmit with `sms_10dlc_brands_submissions_create`.sms_10dlc_brands_deleteDelete a 10DLC brand from the workspace. Irreversible; register a replacement with `sms_10dlc_brands_create` if needed. Fails if a campaign still references the brand; delete those campaigns first with `sms_10dlc_campaigns_delete`.sms_10dlc_brands_getGet one 10DLC brand's business identity details and registration status.sms_10dlc_brands_listList the workspace's 10DLC brands, optionally filtered by registration status. Use `sms_10dlc_brands_get` for one brand's full details.sms_10dlc_brands_requirementsLists what the campaign registry wants before it will accept a brand, in the order to present it, with what you have already supplied and where each item stands. Which fields are required depends on the entity type, so `business_entity_type` is required and the answer is the list for that type. Read it before registering: a registration attempt carries a one-off fee, a rejected brand is corrected and resubmitted with `sms_10dlc_brands_submissions_create`, and that resubmission is charged again. External vetting through `sms_10dlc_brands_vettings_create` is a separate order with its own price, and only for a brand already approved.sms_10dlc_brands_submissions_createResubmit a rejected 10DLC brand with corrected details for registry review. The new details replace what the previous attempt submitted, and the brand returns to the pending state.sms_10dlc_brands_submissions_getGet one submission attempt of a 10DLC brand, including the details that were submitted.sms_10dlc_brands_submissions_listList the submission attempts for a 10DLC brand, most recent first.sms_10dlc_brands_vettings_createOrder external vetting for a 10DLC brand: `standard`, `enhanced`, or `political` for any approved brand, or `auth_plus` for a `public_profit` brand with a `business_contact_email` set (required before its campaigns can run, and never ordered automatically). Charges a one-off fee that varies by class; returns 402 when the wallet cannot cover it. Use `sms_10dlc_brands_vettings_list` to check status.sms_10dlc_brands_vettings_listList every external vetting attempt ordered for a 10DLC brand, across all vetting classes, most recent first.sms_10dlc_campaign_number_links_getGet a 10DLC campaign number link by its own ID, without needing its campaign ID first.sms_10dlc_campaigns_createRegister a 10DLC campaign under an approved brand. A brand registered as a publicly-traded company must hold active Auth+ vetting first. The campaign starts pending while the registry reviews it. Assign the workspace's long codes to it with `sms_10dlc_campaigns_numbers_assign` while it is still pending; they can only start sending once the campaign is approved and the carriers confirm each number. If the registry rejects the campaign, correct the details and resubmit with `sms_10dlc_campaigns_submissions_create`.sms_10dlc_campaigns_deleteDelete a 10DLC campaign from the workspace. Fails if a number is still linked to it; unassign every number first with `sms_10dlc_campaigns_numbers_unassign`.sms_10dlc_campaigns_getGet one 10DLC campaign by ID.sms_10dlc_campaigns_listList the 10DLC campaigns registered for the workspace, optionally filtered by brand.sms_10dlc_campaigns_numbers_assignAssign the workspace's US long codes to a 10DLC campaign so they can send to US recipients once the carriers confirm each number. Either every number in the request is assigned or none is.sms_10dlc_campaigns_numbers_getGet one number registered under a 10DLC campaign and where it stands with the carriers.sms_10dlc_campaigns_numbers_listList the numbers registered under a 10DLC campaign and where each stands with the carriers.sms_10dlc_campaigns_numbers_unassignRemove a number from a 10DLC campaign. The number stops sending to US recipients immediately and is free to assign to another campaign.sms_10dlc_campaigns_requirementsLists what the campaign registry wants before it will accept a campaign, in the order to present it, with what you have already supplied and where each item stands. What is required depends on the use case, so `use_case_category` is required and the answer is the list for that one. Read it before registering: a campaign carries a one-off fee and a recurring charge for as long as it runs, and a rejected campaign is corrected and resubmitted rather than recreated.sms_10dlc_campaigns_submissions_createResubmit a rejected 10DLC campaign with corrected details for registry review. The new details replace what the previous attempt submitted, and the campaign returns to the pending state. A brand registered as a publicly-traded company must hold active Auth+ vetting.sms_10dlc_campaigns_submissions_getGet one submission attempt of a 10DLC campaign, including the details that were submitted.sms_10dlc_campaigns_submissions_listList the submission attempts for a 10DLC campaign, most recent first.sms_destinations_listList every country the SMS service supports, each marked with whether your workspace has enabled it and whether it is currently deliverable. The two are independent: enabling an unsupported country does not make it sendable. The allowlist is default-deny and a workspace starts with only its organization's home country, so a send to any other country is rejected before the sender is resolved. Read this first when a send fails with SMSDestinationNotEnabled. The list is small and returned in full; it is not paginated.sms_destinations_updateEnable or disable destination countries for your workspace. Only the countries you list change; any country you omit keeps its current setting. Enabling one is what lets a send to it past the destination gate; disabling one stops every send there, so confirm a disable with the user first. Each code you enable must be a country the SMS service supports, or the request is rejected and nothing changes; a disable takes any valid ISO code, which is how a country the list no longer shows can still be turned off. Read the destination list first for the current settings and deliverability of the countries it covers.sms_getGet one SMS message by ID: its current delivery status, segment breakdown, cost, and failure detail if it failed.sms_keyword_rules_createReplace the default opt-out, opt-in, or help reply for one country, or add a `custom` keyword. A workspace rule takes precedence over the default for that country. Opt-out and opt-in keywords cannot be assigned to another operation.sms_keyword_rules_deleteDelete one of your own keyword rules, which restores Bird's default for that country and operation. Bird's own rules cannot be deleted.sms_keyword_rules_getRead one default or workspace keyword rule. Its ID prefix identifies which kind: a workspace rule can be changed with `sms_keyword_rules_update`, a Bird default cannot.sms_keyword_rules_listList the default and workspace keyword rules that apply to inbound messages, most specific first. Filter by `country`, `number`, `operation`, or `scope`. Pass `number` to see one number's rules in evaluation order. Default coverage varies by country.sms_keyword_rules_updateChange one of your own keyword rules: its reply, its extra keywords, or its self-managed attestation. Bird's default rules cannot be updated; create your own for that country instead with `sms_keyword_rules_create`. Omitting `keywords` leaves the set alone, while sending an empty list clears your additions back to Bird's.sms_listList SMS messages, newest first, as a cursor page (`data`, `next_cursor`). Pass `next_cursor` back as `starting_after` to fetch the next page. Filter by direction, status, category, recipient, sender, or tag.sms_list_eventsThe lifecycle event timeline for one SMS, oldest first: what happened to it and when. Filter with `type` (for example `sms.delivered`) to keep one kind of event. Use `sms_get` for the message's current state and `sms_list` to find its ID.sms_sendSend one SMS to a single recipient. Supply either `text` (with `category` and `from`) or a stored `template` (by ID or slug, with its `parameters`). The response is the accepted message with its ID; delivery is asynchronous, so use `sms_get` to check status. Browse templates with `sms_templates_list`.sms_send_batchSend up to 100 independent SMS messages in one call. Each item is a full send (free-text or template) with its own ID, status, and cost; all items are validated before any are queued, so one invalid item rejects the batch.sms_senders_createClaims an alphanumeric sender for this workspace, the brand name that shows as the from on a message. Claiming costs nothing. Where a country asks for no registration, the sender can reach it as soon as that destination is enabled on the workspace; everywhere else it needs `sms_senders_registrations_create` first. Which countries ask for what is on `sms_senders_requirements`.sms_senders_getOne sender and where it stands per country. Read it when you already hold the id and want that sender alone; `sms_senders_list` is how you find the id in the first place. A sender blocked on its number's own paperwork says so in `status`, which is a different obstacle from a country wanting a registration.sms_senders_listEvery sender your workspace can send from, dedicated numbers and alphanumeric strings alike, each carrying where it stands per country. Start here when you do not already hold a sender id: nothing else hands you one, and every other read in this area is addressed by it. A sender's `status` says whether it can send at all; `sms_senders_requirements` is where you find out which destinations are open to it and what the closed ones want first.sms_senders_registrations_createRegisters a sender to send to one country. Where the country reviews registrations the record comes back pending and nothing is charged yet; it is billed if and when the registration is approved. Where the country reviews nothing it is approved on this call, and a priced alphanumeric sender is charged its setup fee and its recurring monthly subscription then. Registering a number is free. Neither this operation nor `sms_senders_requirements` quotes a price, so ask whoever owns the account before registering a priced sender. A 402 means the wallet could not cover what was owed at the moment billing ran, a 412 that the organization has an unmet trust gate, and a 409 that a registration for this country already exists in any state other than rejected or suspended, a `pending` one under review included, so a 409 does not mean the sender can send there; a rejected one is resubmitted and a suspended one reactivated by this same call rather than refused.sms_senders_requirementsOne row per country this sender can reach, saying whether a registration is required, where the sender stands with it, and what to do next. Read this before sending from a sender you have not used for a country: holding a number is not the same as being allowed to send from it, and a refused send names this read as its recovery step.sms_stats_by_carrierSMS delivery and latency stats grouped by the carrier that handled the message, ranked by the `sort` metric (default `accepted`) and capped by `limit` (default 50, maximum 200). Use it to compare delivery performance across carriers.sms_stats_by_categorySMS delivery and latency stats grouped by the category you sent under, ranked by the `sort` metric (default `accepted`) and capped by `limit` (default 50, maximum 200).sms_stats_by_countrySMS delivery and latency stats grouped by destination country, ranked by the `sort` metric (default `accepted`) and capped by `limit` (default 50, maximum 200). Use it to find where delivery is worst before drilling into `sms_stats_by_error_code`.sms_stats_by_error_codeSMS stats grouped by our normalized failure reason, which answers which reasons are driving your failures. The grouping key is the same value as the `error_code` filter on `sms_list`, so a row joins straight to the messages behind it. Ranked by the `sort` metric (default `failed`) and capped by `limit`.sms_stats_by_originatorSMS delivery and latency stats grouped by originator, the sender address messages went out from, ranked by the `sort` metric (default `accepted`) and capped by `limit` (default 50, maximum 200). Use it to compare how your senders perform.sms_stats_by_statusHow many messages ended the period in each lifecycle status: accepted, sent, delivered, undelivered, failed, rejected, expired, ordered by count. The "where did my messages end up" view, suitable for a status-distribution chart.sms_stats_by_tagSMS delivery and latency stats grouped by tag (`name:value`), ranked by the `sort` metric (default `accepted`) and capped by `limit` (default 50, maximum 200). Only tagged messages appear, and one carrying several tags counts once under each, so rows do not sum to the period total.sms_stats_dailyOne row of SMS lifecycle counts per calendar day, for charts and trend lines. The window is at most 365 days; set `timezone` to get local calendar days instead of UTC. Rates and latency percentiles are whole-window figures, so read those from `sms_stats_summary`.sms_stats_hourlyOne row of SMS lifecycle counts per hour, for inspecting send rate and deliverability inside a single day. The window is at most 30 days (720 rows) and both bounds round down to the hour. For longer ranges use `sms_stats_daily`.sms_stats_inbound_by_countryMessages your numbers received, grouped by the country of the receiving number.sms_stats_inbound_by_numberHow many messages each of your numbers received, which is the view that shows whether a campaign's reply traffic is landing on the number you expect.sms_stats_inbound_by_operatorMessages your numbers received, grouped by the sender's mobile operator. Messages whose operator the carrier did not report are excluded, so these rows can sum to less than `sms_stats_inbound_summary` for the same period.sms_stats_inbound_dailyMessages your numbers received, one row per calendar day. Set `timezone` to get local calendar days instead of UTC.sms_stats_inbound_hourlyMessages your numbers received, one row per hour, for inspecting inbound volume inside a single day.sms_stats_inbound_summaryTotal messages your numbers received over a period. For a breakdown use `sms_stats_inbound_by_country`, `sms_stats_inbound_by_operator`, or `sms_stats_inbound_by_number`.sms_stats_summaryAggregate SMS KPIs for one period: accepted, sent, delivered, undelivered, failed, rejected and expired counts, the derived delivery and failure rates, and latency percentiles. The `from` and `to` values are both YYYY-MM-DD days or both RFC 3339 instants (hour grain). Add `compare=previous_period` for deltas against the preceding window. For a per-day or per-hour series use `sms_stats_daily` or `sms_stats_hourly`.sms_suppressions_addStop one of your senders from messaging one subscriber. Covers that sender only; your other senders keep reaching them.sms_suppressions_getRead one SMS suppression: the sender and subscriber it covers, why messages are stopped, what it blocks, and whether it is still in force. To check whether you may message someone, filter `sms_suppressions_list` by their number instead.sms_suppressions_listList the workspace's SMS suppressions (sender-and-subscriber pairs blocked from delivery) as a cursor page.sms_suppressions_removeEnd a manual SMS suppression, letting that sender message that subscriber again. Only reason `manual` can be ended this way: a subscriber's own stop keyword and a carrier's opt-out are refused.sms_templates_getGet one SMS template by its slug or ID, including its body and the variables it expects. Fetch it before `sms_send` to see which parameter keys a template send requires.sms_templates_listList the SMS templates available to your workspace, including our built-in templates. Filter by scope, category, or language. The catalog is small and returned in full; this list is not paginated. Use `sms_templates_get` to read one template's variables before sending with it.sms_tfn_verifications_cancelCancels a draft verification and frees the toll-free number it held, so the number can be put on a new one. Only a draft can be canceled: once a verification has been submitted the carrier is holding it, and it is locked.sms_tfn_verifications_createOpens a draft verification against a toll-free sender this workspace owns. Only the sender is required; the dossier is filled in afterwards with `sms_tfn_verifications_update`, over as many calls as it takes. The result is always a draft, and nothing reaches a carrier until it is submitted, which is a step for a person rather than this surface.sms_tfn_verifications_getReads one verification: the state it is in, the sender it licenses, and what the carrier said about it. `denial_reasons` carries the carrier's own words when it declined or asked for more. `status` is what says whether you can still edit it: `draft` and `info_requested` can, `submitted`, `under_review` and `approved` are locked. `resubmit_allowed` answers the one case status cannot, whether a `rejected` verification is still inside its resubmission window.sms_tfn_verifications_listLists the toll-free verifications this workspace holds, newest first. Filter by `status` to separate the drafts still being filled in from the ones a carrier is holding.sms_tfn_verifications_requirementsLists everything the carriers ask for before they will review a toll-free verification, in the order to present it, with what you have already supplied and where each item stands. Read it with no verification named to get the blank form before starting one, or name a verification to see its own answers. An item's `state` says where it stands, and this read emits five: `not_supplied` asks you for the value; `supplied` means a draft holds it; `in_review` means the carrier holds the whole dossier, so nothing can change; `approved` and `rejected` are the carrier's verdict on the dossier, shared by every supplied item, and `reason` carries its words on a refusal. The set is open, since review can gain stages; a state you do not recognise is not yours to act on.sms_tfn_verifications_updateFills in the business and messaging details of a verification that is still editable: a draft, one the carrier sent back asking for more, or a rejected one while its resubmission window is open. Send only the fields that change; anything omitted is left as it was. A submitted, under-review, or approved verification is locked.support_tickets_createOpen a support ticket and return the created ticket. Each call starts a new ticket; send follow-up details as a message on the existing ticket.support_tickets_getRead a support ticket and its full message history. Replies arrive asynchronously; re-read the ticket until a message with `sender_type: agent` appears that was not there before, or the ticket leaves `OPEN`.support_tickets_listList the support tickets opened from this workspace's organization, newest first, each carrying its full message history.support_tickets_replyReply to an existing support ticket by its ID. The response contains only the ticket ID; use `support_tickets_get` for the updated message history.support_tickets_viewedRecord that the authenticated user has seen this support thread. This suppresses a reply-notification email when the user has already read the latest support reply.trust_actions_requirementsLists the trust requirements one action depends on (`buy_number`, `register_sender_id` or `add_sender_id`), each with whether the organization has met it and how to resolve it if not. Read it before offering an action rather than after it refuses: a write gated this way fails with E16000 and names nothing specific, so this is what says which requirement is outstanding. Every requirement must be met before the action is permitted, and the order is a suggestion rather than a sequence. `trust_gates_verification_create` starts a verification against a named requirement, which a one-time code or a provider-hosted link then settles.trust_gates_getOne trust requirement by its slug, with the same fields the list carries. Read it to re-check a single requirement after starting its verification, rather than pulling the whole set.trust_gates_listEvery trust requirement your organization must satisfy before it can acquire numbers or send, and where each one stands. Read it first when an acquisition or a registration is refused for a reason that names a gate rather than a country: `display_status` says whether the requirement is met, and `remediation.kind` says how it gets met: `hosted_verification` and `verify_flow` are yours to act on, `under_review` is a wait with nothing asked of you. `remediation` is null once a requirement is verified.trust_gates_verification_checkSubmits the one-time code a customer received, completing a code-verified requirement. Only when `trust_gates_verification_create` answered with a channel; a provider-hosted requirement is finished in the browser and has no code to submit. Read the gate back afterwards to see the requirement move.trust_gates_verification_createStarts the verification for one requirement, and what comes back decides who finishes it. A provider-hosted requirement answers with `hosted_url`: give that link to the person whose identity is being checked and stop, because only they can complete it. A one-time-code requirement answers with the channel and a masked destination instead, and you continue with `trust_gates_verification_check` once they tell you the code. Send no body for the hosted kind; a code requirement takes the email or phone number to send to.verify_verifications_checkCheck a passcode a recipient submitted. Identify the verification by the same `to` recipient used to start it; no verification ID is needed. A wrong or expired code returns HTTP 200 with `success: false` and a `reason` (for example `incorrect_code` or `expired`). A verification that has already reached a final state is no longer checkable and returns 404, as does a missing verification; malformed input or rate limiting is also an error status.verify_verifications_createStart a verification and send a one-time passcode to the email address, phone number, or both in `to`. Delivery uses one planned channel at a time and fails over when necessary. Calling again for the same recipient reuses the verification in progress and sends after the resend cooldown. The passcode is never returned; submit the recipient's code with `verify_verifications_check`. SMS, WhatsApp, and Telegram delivery draw on the workspace's balance.verify_verifications_next_channelAdvance an in-progress verification to its next channel and send a fresh passcode. Identify it with the same `to` recipient used to create it; no verification ID is required. This bypasses the resend cooldown, and earlier passcodes remain valid. `last_channel` identifies the most recent completed send. `422 NoNextChannel` means the plan is exhausted; create the verification again to resend on the current channel.voice_caller_ids_getFetch one caller ID by ID, with its verification status. Use `voice_caller_ids_list` to find the ID.voice_caller_ids_listList the workspace's caller IDs and their verification status, as a cursor page. Only a verified caller ID may be presented on an outbound call, so an unverified or missing entry here is a common reason a call is refused.voice_destinations_listEvery country the Voice service supports, each marked with whether the workspace has enabled it and whether it is currently callable. A call to a country the workspace has not enabled is refused, so check here when a specific destination fails while others succeed.voice_destinations_updateEnable or disable the countries this workspace may place voice calls to. Only the countries you list change; any country you omit keeps its current setting. Enabling one is what lets a call to it past the destination gate; disabling one refuses every call there, so confirm a disable with the user first. Read `voice_destinations_list` first for the current settings and whether Bird carries calls to the country at all.voice_getFetch one call by ID, at any point in its lifecycle. A call still ringing or connected carries no economics yet: `duration_ms`, `billable_ms`, `ended_at`, and `cost` are null until it ends, and the same ID then returns the settled record. Poll here to watch one known call; use `voice_list` to find calls in the first place. When a call was refused, `rejection_reason` names the gate that turned it away.voice_listList the workspace's calls, newest first. Filter to `ringing`/`in_progress` for the calls in progress right now, to final statuses for completed records, or to any mix of the two. Use `from`/`to` for one known party number in international form, and `number` to search either side by fragment. These are per-call records and do not include aggregate rates or totals. Use `voice_get` to follow one call to settlement.voice_numbers_getFetch one phone number the workspace can use for voice by id: where its calls go, whether it may be presented on an outbound call, and where it came from. Use `voice_numbers_list` to find the id.voice_numbers_listList every phone number the workspace can use for voice, as a cursor page ordered by number. Each entry is one phone number, with where its calls go and whether it may be presented on an outbound call.voice_numbers_updateChange what happens to calls arriving for one number, or the workspace's own label for it. Set the route to `reject` to stop it answering, to `trunk` with a trunk_id to deliver to one of your SIP trunks, or to `forward` with a forward_to and a forward_as to place a call to one of your verified caller IDs. The route replaces whatever was set before, because a number has exactly one answer at a time, and forward_as has no default so state it on every forward. Only a number whose calls arrive at Bird can carry a route.voice_session_credentials_createMint a short-lived SIP digest credential a calling client authenticates with. The password is returned once and cannot be retrieved again.voice_stats_by_countryVoice stats grouped by destination country, ranked by `sort` (default `total_calls`) and capped at `limit` (default 50, max 200); the response's `total` tells a capped ranking from a complete one. Countries sharing a calling code remain separate rows, so a `+1` call to Canada appears under Canada. Calls whose destination cannot be determined collect under a null `country`. For failure causes use `voice_stats_by_response_code`.voice_stats_by_response_codeCall counts grouped by final SIP response code, the "how are my calls ending" view. Successes are rows too (`200` is one), so the rows sum to the whole period rather than to failures, and each row's `share` is against `period_total_calls`. Calls that got no final response collect under a null code. Capped at `limit` (default 50, max 200). This reports SIP outcomes; a call Bird itself refused carries no SIP code that distinguishes the cause, so read `rejection_reason` on the call record with `voice_get`.voice_stats_dailyPer-day voice stats series (total and answered legs, `asr`, `acd_ms`), gap-filled with zero rows so a chart never interpolates, max 365 days. Set `timezone` to bucket by local calendar day instead of UTC. For hour resolution use `voice_stats_hourly`; for one aggregate row use `voice_stats_summary`.voice_stats_hourlyPer-hour voice stats series (total and answered legs, `asr`, `acd_ms`), gap-filled with zero rows, max 30 days (720 rows). A longer window returns 422, so use `voice_stats_daily` for those. `from`/`to` are instants, each rounded down to the enclosing hour and echoed back in `period`. For one aggregate row use `voice_stats_summary`.voice_stats_summaryGet one aggregate row of call-quality and duration metrics. `total_duration_ms` covers every leg; `total_billable_ms` covers answered legs. Use matching day or RFC 3339 bounds, and set `compare=previous_period` for changes against the preceding window. Use `voice_stats_daily` or `voice_stats_hourly` for a series, and the country or response-code breakdowns to locate failures.voice_trunks_createCreate a new SIP trunk for the workspace. Returns the Bird-assigned domain to configure in the customer's PBX or SIP client.voice_trunks_deletePermanently delete a SIP trunk by ID. In-flight calls are not affected; new calls cannot be placed on the trunk after deletion. The trunk's domain becomes available for reuse.voice_trunks_getFetch one SIP trunk by ID: its `domain`, `ip_acls`, `allowed_api_key_ids`, and `routing_configured`. Use `voice_trunks_list` to find the ID.voice_trunks_listList the workspace's SIP trunks as a cursor page. Each carries the Bird-assigned `domain` the customer's equipment sends calls to. The `ip_acls` and `allowed_api_key_ids` fields control which calls are admitted; a trunk with both empty admits nothing. `routing_configured` is false until a carrier route is live for the workspace. Start here when diagnosing why calls are refused.voice_trunks_updateChange a SIP trunk's directions, name, access control and Digest offer. A direction has to be enabled before its settings can be set, and one update can do both, so this is the operation that clears `VoiceTrunkOutboundNotEnabled` and `VoiceTrunkInboundNotEnabled`. The `ip_acls`, `allowed_api_key_ids` and `digest_algorithms` fields each REPLACE their whole list, so read `voice_trunks_get` first and send the list you want to end up with; an empty array clears one. Turning `inbound_enabled` off releases every number the trunk answers and turning it back on does not reclaim them, so confirm that one with the user first.webhooks_attemptsList an endpoint's recent delivery attempts, newest first. Each entry is one HTTP request, so a retried event appears once per try. Pagination uses the `before`/`after` timestamps; page further back by passing the oldest `attempted_at` you received as `before`.webhooks_createRegister an HTTPS endpoint to receive this workspace's events, subscribed to the event types in `events` and active immediately. The response is the only place the signing secret appears, and it can never be read back afterward, only rotated.webhooks_deletePermanently remove an endpoint and stop every delivery to it, including retries of earlier failures. Recreating it later mints a new ID and signing secret; to stop deliveries temporarily instead, set its status to `paused`.webhooks_getRead one endpoint's URL, subscribed event types, and current delivery status. The signing secret is never included, and can only be rotated rather than retrieved.webhooks_listList the workspace's webhook endpoints (URL, subscribed events, status) as a cursor page.webhooks_rotate_secretMint a new signing secret and return it exactly once; it cannot be retrieved afterward. Both the old and new secrets sign every delivery for 24 hours, after which the old one stops signing. An endpoint holds at most 5 valid secrets, so rotating repeatedly inside that window fails.webhooks_testSend a signed synthetic event and get the outcome synchronously: whether the endpoint accepted, the HTTP status it returned, and the round-trip latency. An unreachable endpoint comes back as a failed status in the body rather than a request error. The receiver has 10 seconds, the body is a minimal stub carrying only the event type, and a test reaches even a paused endpoint without being recorded in the delivery attempts.whatsapp_business_accounts_getRead one connected WhatsApp Business Account by its `id` (`waa_` prefix) or the ID WhatsApp reports in `waba`, with the state WhatsApp reports for the account.whatsapp_business_accounts_listList the WhatsApp Business Accounts the workspace has connected, as a cursor page, with the state WhatsApp reports for each. The `waba` a returned account carries is the same value that ties a number to its account, and the one `whatsapp_numbers_list`'s `waba` filter takes.whatsapp_getGet one WhatsApp message by id: current delivery status, sent/delivered/read timestamps, the one content it was built from (a template, or free-form text, image, video, audio, sticker, document or location), and failure detail if it failed. For the per-event timeline use whatsapp_list_events.whatsapp_listList WhatsApp messages, newest first, as a cursor page ({data, next_cursor, …}). Each message carries the one content it was built from: a template, or free-form text, image, video, audio, sticker, document or location. Pass next_cursor back as starting_after to fetch the next page. Filter by direction, status, recipient (to), sender (from), business-scoped user ID (bsuid), template category, or tag. to and from each accept a phone number or a business-scoped user ID; pair either with direction to search a single side of the message. Use whatsapp_get for one message's current state.whatsapp_list_eventsGet one WhatsApp message's delivery timeline, oldest first: whatsapp.accepted, whatsapp.sent, whatsapp.delivered, whatsapp.read, and whatsapp.failed events, with failure detail on failed events. Not paginated; an unknown message ID returns `404`. Use `whatsapp_get` for the condensed current status.whatsapp_mediaDownload the media on a received WhatsApp message. The media ID is the message content object's `id`, from `whatsapp_get`. Up to 5 MiB, media returns inline as a blob; larger media returns a pre-authorized URL valid 15 minutes and needing no Authorization header. Media expires 30 days after the message arrives, when this returns 410; outbound messages carry no stored media.whatsapp_numbers_createConnect a number the workspace already holds to WhatsApp. Take the number's id from `numbers_list`, where a connectable number is a dedicated one (`nda_` prefix) that can receive text messages; WhatsApp proves ownership for you, so no verification code is asked for. The number comes back `preparing` and takes a couple of minutes. Read it back with `whatsapp_numbers_get` until it reports `awaiting_signup`, at which point it carries `finish_setup_url` (a browser flow behind an OAuth screen that a person must complete, and that no operation here can substitute for). `failed` means it could not be prepared and `error` says why.whatsapp_numbers_deleteDisconnect a WhatsApp number from the workspace so it can no longer send.whatsapp_numbers_getRead a WhatsApp number and the state WhatsApp reports for it. `next` says what to do about that state, including the browser step that finishes a connection while `status` is `awaiting_signup`.whatsapp_numbers_listList the WhatsApp numbers the workspace can send from as a cursor page, with each number's WhatsApp state, quality rating, messaging limit and throughput.whatsapp_numbers_precheckCheck whether WhatsApp will accept a phone number before buying it: take a number from `numbers_available_list`, check it here, and order it with `numbers_orders_create` only if this check answers `available`. It is a write rather than a lookup, so check the number you intend to buy rather than sweeping a list of candidates, and reuse an `Idempotency-Key` to get the stored answer back instead of asking WhatsApp again.whatsapp_numbers_profile_getRead the business profile WhatsApp shows to people a connected number messages.whatsapp_numbers_profile_updateChange the business profile WhatsApp shows to people a connected number messages. `username_transfer_action: force_transfer` takes the username off another of the workspace's numbers and the response does not say which, so confirm with a person before sending it.whatsapp_numbers_updateChange your workspace's own label for a connected WhatsApp number.whatsapp_sendSend one WhatsApp message to a single recipient, carrying exactly one kind of content: a template, or free-form text, image, video, audio, sticker, document or location. A template is the only content deliverable outside an open 24-hour customer service window. For a Bird-managed template Bird selects the sender number, so omit from; every other send requires from and it must be a number your workspace owns. `whatsapp_templates_list` carries the names a template send accepts, with the languages each template can currently resolve. The response is the accepted message with its id; delivery is asynchronous, so use whatsapp_get to check delivery status.whatsapp_stats_by_error_codeFailed outbound WhatsApp messages grouped by the normalized failure reason, the same value a failed message reports in `last_error.code`, ranked by volume. This is the read that answers "why are sends failing"; `whatsapp_stats_summary` gives the failure rate, this gives its composition. A send declined before handoff (insufficient balance, missing price, suppressed recipient) counts as rejected rather than failed and is absent here; read `delivery.rejected` on `whatsapp_stats_summary` for it. Rows are the whole workspace's: the breakdown takes no dimension filter. Cap the rows with `limit` (default 50, max 200).whatsapp_stats_by_phone_numberOutbound WhatsApp counts grouped by the business number that sent them, ranked by accepted volume, each row marked as a number your workspace connected or one Bird manages on your behalf. Use it to find the sender behind a delivery problem, then read that number's own state from `whatsapp_numbers_list` filtered by `phone_number`: a row carries the number itself, not its `wan_` id. Rows are the whole workspace's: the breakdown takes no dimension filter.whatsapp_stats_by_tagOutbound WhatsApp counts grouped by the tags a send attached, ranked by accepted volume. A row's tag is `name:value`, so one tag name spreads over as many rows as it has values. Rows are the whole workspace's: the breakdown takes no dimension filter; to see one tag over time, filter `whatsapp_stats_daily` by `tag` instead. Cap the rows with `limit` (default 50, max 200).whatsapp_stats_by_templateOutbound WhatsApp counts grouped by template slug, ranked by accepted volume. Rows sum to less than the period's accepted total: a free-form send resolves no template, and some volume cannot be attributed to one at all, so take the denominator from `whatsapp_stats_summary`. Rows are the whole workspace's: the breakdown takes no dimension filter; to see one template over time, filter `whatsapp_stats_daily` by `template` instead. Cap the rows with `limit` (default 50, max 200).whatsapp_stats_by_template_categoryOutbound WhatsApp counts grouped by Meta's template category (`authentication`, `utility` and `marketing` today, and the vocabulary is open), ranked by accepted volume. Category is what WhatsApp prices a message on, so this is the breakdown that explains a spend change. A free-form send carries no category, so rows sum to less than the period's accepted total; take the denominator from `whatsapp_stats_summary`. Rows are the whole workspace's: the breakdown takes no dimension filter. Cap the rows with `limit` (default 50, max 200).whatsapp_stats_dailyOutbound WhatsApp lifecycle counts, one row per calendar day of the window, gap-filled so a silent day is a zero row rather than a missing one. Every event a message produces counts against the day that message was accepted, so a row is a funnel over that day's sends and recent rows under-report while callbacks arrive. Each row carries its own latency percentiles, but delivery, failure and read rates are whole-window figures: read those from `whatsapp_stats_summary`. Accepts the same single-dimension restriction: `template`, `category`, `phone_number` or `tag`. Days are calendar days in `timezone`, or UTC when it is omitted. Max window 365 days; `from` and `to` default to the trailing 30 days.whatsapp_stats_hourlyOutbound WhatsApp lifecycle counts, one row per hour, gap-filled. Every event a message produces counts against the hour that message was accepted, so a row is a funnel over that hour's sends and recent rows under-report while callbacks arrive. Each row carries its own latency percentiles, but delivery, failure and read rates are whole-window figures: read those from `whatsapp_stats_summary`. Use it where the daily grain hides the shape; a window spans at most 720 hours (30 days), and for anything longer use `whatsapp_stats_daily`. Accepts the same single-dimension restriction: `template`, `category`, `phone_number` or `tag`. `from` and `to` are optional RFC 3339 instants, defaulting to the trailing 168 hours.whatsapp_stats_inbound_by_phone_numberReceived WhatsApp message counts grouped by the business number that received them, ranked by volume. Use it to see which of your numbers customers actually write to. Cap the rows with `limit` (default 50, max 200).whatsapp_stats_inbound_dailyReceived WhatsApp message counts, one row per calendar day of the window, gap-filled so a silent day is a zero row. Days are calendar days in `timezone`, or UTC when it is omitted. Max window 365 days; `from` and `to` default to the trailing 30 days.whatsapp_stats_inbound_hourlyReceived WhatsApp message counts, one row per hour, gap-filled. A window spans at most 720 hours (30 days); for anything longer use `whatsapp_stats_inbound_daily`. `from` and `to` are optional RFC 3339 instants.whatsapp_stats_inbound_summaryAggregate count of the WhatsApp messages your workspace received in one window, with the delta against the window immediately before when `compare` is set to `previous_period`. Inbound is counted separately from outbound: this answers "how much are customers writing to us", where `whatsapp_stats_summary` answers "how much are we sending".whatsapp_stats_summaryAggregate outbound WhatsApp counts for one window: accepted, sent, delivered, failed and rejected, with delivery and failure rates, read engagement, and processing and end-to-end latency percentiles. Restrict it to one dimension with `template`, `category`, `phone_number` or `tag`, one at a time, not combined. Set `compare` to `previous_period` for the deltas against the window immediately before. `from` and `to` are optional and default to the trailing 30 days. Counts are attributed to the time each message was accepted, so a delivery confirmed today counts against the day its message was accepted; `period.data_as_of` is the freshness boundary the rollups have reached.whatsapp_templates_getGet one WhatsApp template by slug or ID: its handle, its lifecycle, and where each of its languages stands. Content is not included; use `whatsapp_templates_versions_get` for that.whatsapp_templates_listList the workspace's WhatsApp templates: each template's handle, its lifecycle, and where each of its languages stands. Content is not included; use `whatsapp_templates_versions_get` for that.whatsapp_templates_versions_getGet one version of a WhatsApp template: its submission state and the languages it carries. This is the level at which content exists.whatsapp_templates_versions_languages_getGet one language of one WhatsApp template version: its content blocks, what this version's submission did with it, and Meta's review outcome and category for it.whatsapp_templates_versions_languages_listList the languages one WhatsApp template version carries, with each language's review outcome at Meta and a content hash to tell which ones actually differ before fetching any of them. Use `whatsapp_templates_versions_languages_get` for a single language's content blocks.whatsapp_templates_versions_listList a WhatsApp template's versions, newest first. Each version is one immutable submission; an open draft, if one exists, appears alongside them. Use this to find the version a send resolves to, or the draft still being edited.whoamiRead the identity behind the current credential, whether that is a browser session or an access token acting for a user. Returns `401 Unauthorized` when the request carries no valid credential.workspace_getFetch the current workspace's name, ID, and organization. This is the workspace the current credentials are scoped to.workspace_settings_getRead the workspace's effective feature settings: platform defaults overlaid with whatever the workspace has changed. Today that covers email content storage (`email.storage_enabled`, default `true`).
Last checked Oct 19, 2026
[ features ]
AI Engine Coverage
Coverage and support for various AI models, LLMs, and search engines.
List of AI models and LLMs supported for tracking (e.g., ChatGPT, Gemini).
How often metrics are updated (e.g., real-time, daily).
Support for tracking in multiple countries or regions.
Monitoring Metrics
Key performance indicators and analytics provided for brand presence.
Tracks brand mention frequency or share in AI responses.
Monitors brand's ranking or position in AI-generated results.
Compares brand performance against competitors.
Identifies sources cited in AI responses for the brand.
Optimization Tools
Features for improving brand presence through content and strategy adjustments.
Provides tailored suggestions for content to boost AI visibility.
Allows users to define and track custom customer-like queries.
Integrations and Pricing
Ecosystem compatibility, extensibility, and cost structure.
Pre-built connections to popular tools.
Offers a free trial period for testing.
Publicly listed pricing without requiring contact.
Compare With
Reviews
No reviews yet. Be the first to review MentionBird!