MCP server
Connect an AI agent to your Voidhash analytics and paywall workspace.
The Voidhash MCP server connects an AI agent to your project. A compatible agent can read revenue, subscription and trial analytics and ad campaign performance, and inspect and edit paywalls, write components, and render previews. This page shows how to create credentials, point your client at the server, and confirm that it works.
Server
The server runs at one URL:
https://api.voidhash.com/api/mcpIt uses streamable HTTP as its transport and bearer authentication, so the client sends a key in
the Authorization header on every request.
The server implements the stateless MCP protocol, version 2026-07-28. Each request stands on its
own, with no initialization handshake or session to keep alive. Clients that support only the
earlier session-based versions cannot connect.
Tools
The server groups its tools into toolsets. A request lists, and can call, only the tools its credential has permission for, so the same server serves a read-only reporting agent and a paywall designer.
| Toolset | Tools | Permission |
|---|---|---|
| Analytics | list_insights, run_insight, acquisition_report | project:analytics:read |
| Ads | ads_overview, campaign_performance, ads_issues, ads_cohorts, list_ad_campaigns | project:ads:read (and project:analytics:read for Voidhash numbers) |
| Paywalls | list_paywalls, list_products, list_fonts, bash, list_components, read_component, get_component_build | project:paywalls:read (project:products:read for products) |
| Paywalls | begin_paywall_edit and every tool that uses its edit session, create_product, write_component | project:paywalls:write (project:products:write for products) |
Tools that only read are marked with MCP's read-only annotation, so clients can run them without asking for confirmation.
Analytics
list_insights returns the built-in insights, such as revenue, MRR, active subscriptions, trials,
trial conversions and churn, with what each measures, its unit, and the time ranges, granularities
and filters it accepts. run_insight runs one insight with the same inputs as the
insights endpoint: a time range preset such as
last_30d or a custom start and end, a granularity, and an optional filter. It returns the
period it covered, a summary, and one value per bucket, with the unit:
{
"insightId": "builtin/revenue",
"unit": "USD",
"environment": "production",
"period": {
"start": "2026-10-01T00:00:00.000Z",
"end": "2026-10-08T00:00:00.000Z",
"granularity": "day"
},
"summary": { "value": 1250.4, "meaning": "total over the period" },
"series": [{ "start": "2026-10-01T00:00:00.000Z", "value": 180.25 }]
}Amounts are in US dollars and net of refunds, rates are percentages, and periods are in UTC.
run_insight reports production purchases only, unlike the insights endpoint. To include sandbox
purchases, filter on provider.environment yourself (1 is production, 2 sandbox); the result's
environment field shows whether the production default applied.
acquisition_report takes the same inputs as the
acquisition endpoint: a from and to
day, the level to group by (network, campaign, adset, ad or surface), and optionally a
network, campaign, ad set or ad filter, currency, time zone, revenue window, key conversion and
environment. Each group reports the visits its ads brought, the people who signed up after their
first touch, their app installs, trials, payers and revenue, with the ad platform's campaign, ad set
and ad IDs, so an agent can join them to the spend it reads from the ad platform. The report also
has a funnel by surface, where payers paid, and how much revenue can be traced to a first touch.
Amounts are in the requested currency. returningPeople were reached by a touch but were already
known, so they are not counted as acquired. Revenue comes from production unless you set
environment. See ad measurement for the definitions.
Ads
When the project has a connected Meta ad account, the ads tools report paid acquisition the way the Ads pages in Studio do. Every tool only reads.
| Tool | What it returns |
|---|---|
ads_overview | Spend, net revenue, people acquired, key conversions, cost per key conversion and ROAS, with the previous period; spend and revenue by day; the funnel by surface; where payers paid; each platform next to organic and other sources; issues to look at. |
campaign_performance | One row per campaign, ad group (Meta's ad set) or ad with delivery and its reason, destination, budget, the platform's numbers and Voidhash's numbers, plus totals over every matching row. |
ads_issues | Rejected ads, learning-limited ad groups, objects that are on but not delivering, account problems, spending limits close to the cap, failed syncs, and active ads whose links miss the tracking parameters. |
ads_cohorts | Weekly or monthly cohorts of the people your connected ad platform brought in (organic people are not included), with ROAS (or revenue per payer, or payers) at days 0 to 90 after acquisition, and the day each group pays back. |
list_ad_campaigns | The synced campaigns with delivery, reasons, destination, objective, optimization event, bid strategy and budget, and each ad account's currency, time zone, status and sync status. |
Agents that called the first version of campaign_performance need to change; see the list below.
Changes to campaign_performance:
adAccountIdandrevenueWindoware removed. A call that still passes one fails with a message naming its replacement:list_ad_campaignswithadAccountIdfor one account's campaigns, andads_cohortsfor revenue by day after acquisition. Revenue is to date.- Each row keeps the platform's numbers in
platformand Voidhash's invoidhash.roasis nowvoidhash.trueRoas,metaRoasisplatform.platformRoas, andcostPerAcquisitionisvoidhash.costPerSignup. - Rows cover synced campaigns, ad groups and ads only. People attributed to IDs no account has
synced are no longer separate rows, and account spend that no ad row accounts for (such as
deleted ads), formerly
unallocated, is no longer part of the totals; the overview's spend still includes it. leveltakesad_group(adsetis still accepted). A range is arangepreset or bothfromandto; one without the other is refused.
Two sources, never blended. Every row keeps two objects apart. platform holds what the ad
platform reports with its own attribution: spend, impressions, link clicks, CTR, its purchase value
and ROAS, and its results with their type. voidhash holds what Voidhash measured for the people
whose first touch came from the ad: visits, app installs, signups, trials, payers, key conversions,
and gross, refunded and net revenue to date. Spend is the one platform number Voidhash's ratios use.
| Metric | Definition |
|---|---|
| People acquired, signups | People who signed up after a first touch from the ad, counted once. |
| Key conversion | The step the project measures cost against: signup, trial or payer (payer by default). |
| Net revenue | Revenue after refunds from those people, to date, in the report currency. |
| True ROAS | Voidhash net revenue ÷ spend. The platform's ROAS (its purchase value ÷ spend) is shown beside it. |
| Cost per step | Spend ÷ the people Voidhash measured at the step: cost per signup, payer or key conversion. |
| Cost per link click | Spend ÷ the platform's link clicks; both numbers come from the platform. |
| Cohort ROAS | A cohort's cumulative net revenue ÷ the spend on the days its people were acquired. Curves only rise, except through refunds. |
Totals add only what adds up. Reach and frequency are per row and never summed, because one person can see ads from many rows, and results of different types, such as landing page views and app installs, are listed apart rather than added. Steps a project does not use are left out, so a web-only project has no installs and an app-only project has no visits, and website ads never report installs.
ads_overview, campaign_performance and ads_cohorts take a range preset (last_7_days by
default, last_13_weeks for cohorts; the last_* presets end yesterday) or both from and to
days, and optionally compare, platform, currency, timezone and environment.
list_ad_campaigns and ads_issues report current state and take no range. campaign_performance
reads reach and frequency per row only with includeReach, and hides ended objects only when they
had no delivery in the range. Money defaults to the ad accounts' currency, converted at each day's rate when you ask
for another, and days to the ad accounts' time zone. Revenue comes from production unless you choose
another environment. Days from provisionalFrom on are still changing, as the platform keeps
attributing conversions to them. Read warnings before acting on the numbers: each has a code,
such as sync_failed, currency_converted or reach_limited, and the details that go with it.
Spend in the overview is the ad accounts' total; the part no ad accounts for, such as deleted ads,
is listed separately.
Voidhash numbers need project:analytics:read as well. Without it, the tools still answer with the
platform's numbers and say what is left out, and ads_cohorts explains that it needs the
permission. The analytics read-only key has both permissions.
Create credentials
For a single project, use a secret key of the project and keep it out of source control. An agent that only reports on your business needs no more than a key with Read-only analytics access, which sees only the analytics and ads tools; see Limit what a secret key can do. Send the key as a bearer token:
Authorization: Bearer vh_sk_...A user key can access several projects, so the server also needs to know which one you mean. Send the project ID or slug in a second header:
Authorization: Bearer vh_...
X-Voidhash-Project: my-projectThe CLI can print these headers for the current login. This keeps the key out of a command argument:
npx voidhash-cli auth token --project my-projectConfigure your client
In your MCP client, add a remote or streamable HTTP server named voidhash, then set the URL and
headers from above. Clients that use JSON configuration commonly accept this shape:
{
"mcpServers": {
"voidhash": {
"type": "http",
"url": "https://api.voidhash.com/api/mcp",
"headers": {
"Authorization": "Bearer vh_sk_..."
}
}
}
}Configuration keys differ between clients. Some expect servers instead of mcpServers, or
serverUrl instead of url. In those cases, follow your client's own remote MCP instructions.
Verify the connection
Ask the agent a question that needs the server:
What paywalls do I have in Voidhash?
The agent should call list_paywalls and return the current project's paywalls. With a read-only
analytics key, ask for a metric instead, such as "What was my revenue over the last 30 days?", and
the agent should call run_insight. If it receives a 401, replace the key. If a user key
authenticates but no project is selected, add the X-Voidhash-Project header. If a tool you expect
is missing, the credential lacks its permission.
A full-access key lets the MCP server modify project content. Give each agent a key with only the access it needs, store it in your client's secret storage, and rotate it whenever a device or configuration is shared.