Build on Influensia

Everything you can do in the Influensia app you can do over the API: browse verified link and channel inventory, vet sellers, propose escrowed orders, follow fulfilment, and monitor every purchased link. The web app is just one client — this guide is for the other kind: your scripts, your integrations, and AI agents working on your behalf.

Overview

There are two surfaces, backed by the same service layer and the same permissions — an agent can never do more through MCP than its owner can do in the app:

  • REST API — resource-oriented, for your own code. The OpenAPI document is the contract of record; every request and response shape, with examples, lives there.
  • MCP server — task-level tools for AI agents over the Model Context Protocol (Streamable HTTP). One tool call does what would take an agent five REST round-trips.

Pointing an agent at Influensia? /llms.txt is the one-page orientation written for it — what the platform is, how to authenticate, and a numbered “start here” path. It is kept in lock-step with the tool registry by a test, so it never lies about what exists.

Authentication

Create an API key in Settings → API keys. Keys are prefixed flu_, shown once, and hashed at rest. A key belongs to you and one workspace: everything an agent does with it lands in the audit log with a human owner attached, and a buy-side key cannot act in your sell-side workspace (or vice versa) — switch workspace, create a key there.

SurfaceSend the credential as
REST (/api/v1)x-api-key: flu_…
MCP (/api/mcp/mcp)Authorization: Bearer flu_…
MCP clients that speak OAuthNo key needed — the server supports MCP OAuth with dynamic client registration; you consent in your normal Influensia session
  • Workspace selection — pass X-Workspace: <id|slug> on any REST call; otherwise the key's workspace applies.
  • Hygiene — treat keys like passwords: server-side only, never in a browser bundle or a repo. Per-key expiry is available; revoke from the same settings panel.

Quickstart

1 · Confirm the credential

Always start with GET /api/v1/me (MCP: whoami) — it returns who you are, the active workspace, its kind (buy-side client or sell-side provider) and your role in it. Everything else depends on that context.

The public half of that identity is GET /api/v1/me/profile (MCP: get_my_profile) — the same shape as GET /api/v1/users/{handle} but addressed by credential, so it answers before a handle has been claimed. Write it back with PATCH /api/v1/me/profile (MCP: update_my_profile): headline, location, bio, services, niches, handle and colour mode, any subset per call. Read before you write — a member edits the same fields in their settings, and a patch is a replace, not a merge.

curl https://influensia.com/api/v1/me \
  -H "x-api-key: flu_YOUR_KEY"

2 · Find inventory

The canonical domain registry answers “who sells a link on this site, at what price, on what terms” — same domain from many providers, one comparison, cheapest first. Each offer carries that seller's own content terms (per-word rate, word tiers, writing languages).

curl
curl "https://influensia.com/api/v1/domains/example-magazine.com" \
  -H "x-api-key: flu_YOUR_KEY"

Metrics belong to the domain, not to the offer. dr, da, traffic, refDomains, spamScore and organicKeywordsare identical on every offer for one site: they are read from the shared registry whenever any seller's connected data provider has checked it, and from the selling seller's own claim only while nobody has. verified tells you which, verifiedBy names the providers and metricsCheckedAt says when they last read it. Two fields sit outside that rule, in opposite directions. trafficValue has no verified counterpart anywhere, so treat it as a claim. trend has no CLAIMED counterpart: +1 rising or -1 declining is derived from two of our own monthly readings of the site, and it is null — the common case — whenever we have not measured a direction ourselves. Nobody can state one, so a null there means unmeasured, never flat. Compare offers on price, delivery, link terms and content terms; comparing their metrics is comparing a site to itself.

Broader discovery: GET /api/v1/domains is the faceted directory search, GET /api/v1/markets browses seller storefronts, and GET /api/v1/channels lists verified social channels sold alongside links. Filters and facet counts are documented per-endpoint in the API reference.

Vetting the people behind the inventory: GET /api/v1/users/{handle} is the full member profile, and GET /api/v1/users/verified?ids=… is the identity question alone, batched — a map of user id to boolean for up to 100 ids, where ids that don't resolve read false rather than erroring. It answers for the person. The workspace-level Verified business badge is a different fact and travels on market and offer payloads as sellerVerified — on the LIST shapes too, so a browse can be filtered on it without a detail call per market.

A market's policies array is two lists spliced together. The platform's own chips come first and are computed from the inventory on every read, so they cannot outlive the fact behind them: 12-month link guarantee appears only when every listing currently on sale is sold for 12 months or longer (a permanent link, sent as durationMonths: null, counts). One shorter listing and the chip is gone. Everything after them is the seller's own prose — "No PBNs", "Disclosure compliant" — which nothing checks. A seller cannot mint a platform chip by typing its wording: the label is stripped from their text before the derived list is prepended. Report the two kinds differently.

3 · Propose an order

Every link placement is created with its brief — the anchor text and target page are the agreement the platform later verifies the published link against. Briefs are keyed by listing id; targetPage may be omitted only when campaignId names a campaign with a site (the homepage becomes the target). The brief also names the placementNiche — default standard; a priced vertical from the listing’s own nichePrices(crypto, casino, …) re-prices the item from that variant, and a vertical the listing doesn’t accept refuses the order. The item snapshots the listing’s dofollow/sponsored/duration terms at creation. Always send an Idempotency-Key so retries are safe.

curl
curl -X POST https://influensia.com/api/v1/orders \
  -H "x-api-key: flu_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 0d6f2c9a-first-order" \
  -d '{
    "marketId": "MARKET_ID",
    "domainIds": ["LISTING_ID"],
    "campaignId": "CAMPAIGN_ID",
    "briefs": {
      "LISTING_ID": {
        "anchor": "best crm for startups",
        "targetPage": "https://yoursite.com/crm",
        "notes": "Mention the free tier; no competitor comparisons."
      }
    }
  }'

The response is the created order with status requested a proposal, not a purchase. A human funds escrow through checkout in the app; work starts only then. Poll GET /api/v1/orders/{id} (MCP: get_order_status) to follow per-placement fulfilment — each item moves queued → writing → review → publishing → live, and escrow releases per link.

REST conventions

These hold on every /api/v1 endpoint, so client code can be written once.

Errors — RFC 9457 problem+json

Every error is application/problem+json: a stable type URI, a human title, and a detail that says what to change, not just what failed. Validation errors add a field-level errors map. A 429 always carries Retry-After (seconds):

HTTP
HTTP/1.1 429 Too Many Requests
Retry-After: 41
Content-Type: application/problem+json

{
  "type": "https://influensia.com/problems/rate-limited",
  "title": "Rate limit exceeded.",
  "status": 429,
  "detail": "Limit is 240 requests per 60s. Retry after 41s."
}

Retry guidance: honor Retry-After on 429; back off and retry on 5xx; treat every other 4xx as yours to fix — repeating the request unchanged will not help.

Idempotency

Every POST accepts an Idempotency-Key header (any unique string, 24h window). The same key with the same body replays the stored response with Idempotency-Replayed: true; the same key with a different body is a 409. Only sub-500 responses are stored, so failed requests stay retryable. For anything that creates an order, sends a message, or moves state: always send one.

Pagination

Cursor-based everywhere: ?cursor=&limit= (default 25, max 100), response { items, nextCursor }. Ids are time-ordered uuidv7, so cursors sort chronologically. There is no offset pagination.

HTTP
GET /api/v1/orders?limit=25
→ { "items": [ /* 25 orders */ ], "nextCursor": "0198c5d2-…" }

GET /api/v1/orders?limit=25&cursor=0198c5d2-…
→ { "items": [ /* next page */ ], "nextCursor": null }

Rate limits

240 requests per minute per credential, in a fixed window. Budget for bursts, honor Retry-After, and prefer the task-level MCP tools when driving an agent — one tool call replaces several REST calls.

Plan allowances

Almost nothing here is metered — listings, orders, messages and search are unlimited on every plan, because the platform fee is the business model. Projects are the exception. A project is one website, and registering one buys that domain’s authority and backlink baseline from a paid vendor on our account, refreshed monthly for as long as the project lives. So the plan caps them: Free tracks 1 website, Pro tracks 10.

POST /api/v1/projects answers 409 once the allowance is spent. Two details matter for a client that has to handle it. Archived projects count — they still hold their domain, so archiving frees nothing. And on Free, DELETE /api/v1/projects/{id} always reports {"outcome": "archived"} rather than erasing, which means no sequence of calls returns a slot. The way to track a different domain on a full workspace is PATCH /api/v1/projects/{id} with a new site, accepted until that project has campaigns and costing nothing; otherwise the workspace owner upgrades in Settings → Billing.

Versioning

/v1 is additive-only: fields and endpoints are added, never removed or re-typed. A breaking change would ship as /v2 beside /v1 with a documented sunset of at least six months. Write clients that tolerate unknown fields.

Writes return the resource

Mutations return the changed resource, not {ok: true} — chain on the returned ids instead of re-fetching.

The MCP server

https://app.influensia.com/api/mcp/mcp — Model Context Protocol over Streamable HTTP, stateless: every tool call is self-contained, so serverless and multi-session clients work without ceremony. The design principles, because they shape how your agent should use it:

  • Task-level, not CRUD. request_order takes the market, the listings and the briefs in one call. If your agent is chaining five reads to do one job, look for the tool that does the job.
  • Human-meaningful identifiers. get_market accepts a slug, compare_domain_offers a domain name, get_member_profile a handle — tools resolve to internal ids themselves.
  • Errors are the recovery path. When an input is wrong, the error text says what to call instead (for example, request_order lists the listings it did not recognise and points at get_market).
  • Unknown is never bad news. Absent metrics mean “not measured”, a pending link check means “not yet checked”, a null completion rate means “new seller”. Reporting unknowns as failures is the one mistake the tool descriptions warn about hardest.
Confirm-mode over MCP executes immediately. In the in-app assistant, tools marked confirm pause for an in-chat Approve/Decline. Over MCP there is no such pause — your API key is the user's standing consent. For the cost-bearing ones (redeem_reward spends a no-refund balance, tip_post moves credits to another member with no undo, refresh_domain_metrics spends the seller's own third-party API budget), the rule is: call them only when the user explicitly asked, never speculatively.

Tool catalog

108 tools. The roster you are SERVED depends on your workspace: a buying workspace gets the buy-side tools, a selling one the sell-side, and the shared tools appear in both. read tools are always safe; write tools change state the user can undo in the app; confirm tools are externally visible or cost-bearing (see the note above).

77 tools on this side.

Account Who am I, what plan, what balance. Money never moves through MCP.

whoamireadIdentity, active workspace, role and every membership. Call this first.
get_billing_summaryreadPlan, billing interval (monthly or yearly), renewal and seats — read-only.
list_billing_historyreadOrder payments and subscription invoices, with receipt / invoice PDF links.
get_rewards_summaryreadCredit balance, badges and quest standing, reconciled on read.
redeem_rewardconfirmSpend credits on pro_month, fee_voucher or market_boost. No refunds — only on an explicit user ask.
tip_postconfirmTip credits to a feed post's author — capped per day, no undo. Only on an explicit user ask.
get_my_profilereadYour own profile, by credential rather than handle — so it answers before a handle exists. Read it before writing it.
update_my_profilewriteName, handle, headline, location, bio, services, niches, colour mode. Each field replaces, never merges.
get_notification_prefsreadWhich kinds are on, and the digest frequency.
update_notification_prefswriteSwitch kinds on or off. Security notices ignore them by design.
tip_commentconfirmSame for a comment's author — one shared daily budget with tip_post.

Buying Find inventory, vet sellers, propose orders. Funding stays human.

get_marketreadOne market with inventory, seller trust stats, content terms and policy chips (derived first, seller prose after). Accepts a slug.
find_domainsreadFaceted directory search — DR/DA/traffic/spam-score/referring-domain filters, counts and facet suggestions.
compare_domain_offersreadEvery seller's offer on one domain name, cheapest first. Takes the bare name.
find_channelsreadBrowse verified social channels (YouTube, Instagram, TikTok, X) with priced formats.
get_channelreadEvery seller's offer on one channel — identity is (platform, handle).
get_member_profilereadVet a member by handle: verification, live stats, reviews.
request_orderconfirmPropose an order — link and channel placements, briefs inline. Creates a PENDING request; a human funds escrow.
get_order_statusreadOne order with per-item lifecycle and escrow state.
list_ordersreadOrders with status and date filters.
list_order_itemsreadThe flat incomplete-work queue across all orders.
cancel_orderconfirmUn-propose a pending order before money moves.
advance_order_itemconfirmMove a placement through its lifecycle. mark_live is the claim escrow acts on — releasing is still human-only.
set_order_item_briefconfirmAnchor, target page and content guidance for a placement. Freezes when the link goes live.
get_basketreadThe workspace's shared basket — the multi-seller path. Paying stays human.
add_basket_itemwriteAdd a link or channel listing, pinned to a campaign on the line.
set_basket_item_briefwriteAnchor, target and content mode — checkout refuses an un-briefed link line.
set_basket_campaignwritePin every line to one campaign at once.
remove_basket_itemwriteTake one line out. It's a shared basket — the line may be a teammate's.
clear_basketconfirmEmpty it completely, teammates' lines included. No undo.
list_reviewable_ordersreadReleased orders still owed a review.
write_reviewconfirmPublic and permanent, one per order — no edit, no delete.
set_auto_releaseconfirmThe buyer's auto-release policy: verified live links release their own escrow.

Selling Fulfilment and data quality for provider workspaces.

list_market_inventoryreadOne market’s listings, filtered and paged — the ids update_listing takes.

Messaging The deal thread. Priced offers stay human-composed.

list_conversationsreadThreads with unread state.
read_conversationreadThe messages in one thread, with shared markets and offers. Read before replying.
open_conversationconfirmOpen (or reuse) a thread with a market's seller.
send_messageconfirmSend a message — body plus an optional market reference. Deliberately no offers or files.

Work Projects, campaigns, content and the demand board.

list_projectsreadWebsites and their portfolio rollup — one project per registrable domain.
get_project_healthreadWhich websites need attention and WHY, ranked worst first.
create_projectwriteRegister a website as a project. 409 once the plan allowance is spent — Free 1, Pro 10, archived included.
update_projectwriteRename, change status, archive, or re-point the domain while it has no campaigns.
remove_projectconfirmErases a website nothing has ordered against; archives it otherwise (always, on Free), and says which.
list_campaignsreadCampaigns, filterable by project and status.
create_campaignwriteStart a campaign inside a website, guardrails and all.
update_campaignwriteGoals, guardrails, status.
remove_campaignconfirmSame two outcomes as remove_project — the board and its orders are kept either way.
get_campaign_reportreadOne campaign's numbers: placements, spend, links live.
get_campaign_insightsreadAI reading of one campaign (Pro) — every insight cites a measured signal.
recommend_placementsread"What should this campaign buy next", from its own guardrails. Prefer it over find_domains when a campaign is in play.
add_campaign_placementswriteShortlist domains as prospects — no money, no order.
create_documentwriteDraft a document inside a campaign.
list_documentsreadA website's documents — titles and status, no bodies.
get_documentreadOne document with its body — including an order item’s draft.
update_documentwriteRewrite title, status or the whole body. No append — send the full text.
list_feedreadRead the community feed create_feed_post writes into.
publish_articleconfirmAn article under the user's byline. Drafts by default; a human decides whether it goes out.
create_feed_postconfirmPost to the community feed.
list_my_articlesreadYour articles, drafts included.
get_articlereadOne article by slug, with its body.
update_articlewriteRevise title, kicker, format or the whole body.
unpublish_articleconfirmBack to a private draft; republishing keeps the same URL.
list_briefsreadThe demand board — open briefs; sellers pass matchingMyInventory to see what their live listings could fill.
publish_briefconfirmPublish what a campaign needs; sellers answer with priced offers. Answering has no tool on purpose.

Team & access Who is in the workspace, and what guests can reach. Grants only matter for guests.

list_workspace_membersreadEveryone, with role and presence.
list_invitationsreadPending and past invitations.
invite_memberconfirmSends an email. Guests see nothing until a grant reaches them.
list_accessreadEvery grant, or one subject's list with inherited reach marked.
share_accessconfirmShare one project, campaign or order — may send an invitation.
revoke_access_grantconfirmA guest with no grants left sees nothing at all.

Insight Reporting, search and the link-verification read side.

get_analytics_summaryreadWorkspace reporting rollups for a window you choose.
get_analytics_insightsreadAI reading of the workspace's reporting (Pro).
searchreadCross-entity search: markets, domains, orders, campaigns, people.
check_link_healthreadAre the links we bought still up. `pending` means UNKNOWN — never report it as broken.
request_link_recheckwriteQueue an immediate re-verification of a placement.
list_notificationsread"What needs my attention" — the bell inbox, with an href per row.
mark_notifications_readwriteClear the badge, one row or all. No way to mark unread again.

Connect a client

Claude Code

One command, project-scoped so your team gets it from the repo. The ${FLU_API_KEY} form resolves the key from the environment at startup instead of committing it:

shell
claude mcp add --transport http influensia https://app.influensia.com/api/mcp/mcp \
  --header "Authorization: Bearer ${FLU_API_KEY}" \
  --scope project

Or check the equivalent .mcp.json into the project root:

.mcp.json
{
  "mcpServers": {
    "influensia": {
      "type": "http",
      "url": "https://app.influensia.com/api/mcp/mcp",
      "headers": { "Authorization": "Bearer ${FLU_API_KEY}" }
    }
  }
}

claude.ai and Claude Desktop

Add a custom connector (Settings → Connectors → Add custom connector) with the server URL https://app.influensia.com/api/mcp/mcp. Custom connectors authenticate with OAuth — no API key needed: the server registers the client dynamically and you approve the connection in your normal Influensia web session.

Claude API — MCP connector

Building your own product on the Claude API? Attach the server straight to a Messages call — Anthropic makes the MCP connection server-side, and the model gets every tool below without any client-side plumbing:

import Anthropic from '@anthropic-ai/sdk';

const anthropic = new Anthropic();

const response = await anthropic.beta.messages.create({
  model: 'claude-opus-5',
  max_tokens: 16000,
  betas: ['mcp-client-2025-11-20'],
  mcp_servers: [{
    type: 'url',
    name: 'influensia',
    url: 'https://app.influensia.com/api/mcp/mcp',
    authorization_token: process.env.FLU_API_KEY, // flu_…
  }],
  tools: [{ type: 'mcp_toolset', mcp_server_name: 'influensia' }],
  messages: [{
    role: 'user',
    content:
      'Compare every offer on example-magazine.com, vet the sellers, ' +
      'and draft an order proposal for the best one.',
  }],
});

Claude Agent SDK

For agents you host yourself (the Claude Code harness as a library), declare the server in mcpServers and allowlist its tools:

TypeScript
import { query } from '@anthropic-ai/claude-agent-sdk';

for await (const message of query({
  prompt: 'Which of our purchased links lost their live status this week?',
  options: {
    mcpServers: {
      influensia: {
        type: 'http',
        url: 'https://app.influensia.com/api/mcp/mcp',
        headers: { Authorization: `Bearer ${process.env.FLU_API_KEY}` },
      },
    },
    allowedTools: ['mcp__influensia__*'],
  },
})) {
  // stream progress / read the final result
}

Everything else

Any MCP client that speaks Streamable HTTP works: point it at https://app.influensia.com/api/mcp/mcp and send Authorization: Bearer flu_…. Clients that implement MCP OAuth can skip the key entirely.

Agent playbooks

Worked tool sequences for the jobs people actually delegate. Each starts from whoami.

Vet and buy (buyer)

  1. find_domains or search_markets to shortlist, then compare_domain_offers per domain — same site, every seller's price and terms.
  2. get_market and get_member_profile to vet: verification badges, live stats, reviews. A null completion rate is a new seller, not a bad one.
  3. request_order with briefs inline — and pass campaignId when the user's intent names a campaign: an order's campaign is set at creation and can never be attached afterwards.
  4. Hand off: a human funds escrow in checkout. cancel_order is the undo while the order is still pending.

Campaign-driven buying

  1. list_campaignsrecommend_placements — “what should this campaign buy next”, from the campaign's own guardrails; it already excludes domains that link to the project. Prefer it over find_domains, which knows nothing about the campaign.
  2. add_campaign_placements to shortlist prospects (no money), or go straight to request_order with campaignId.

Link-health watch

  1. check_link_health — every purchased placement, re-verified on a widening schedule (1, 3, 7, 30, then every 90 days). verified means the link was seen; failed means real evidence it is wrong or gone; pending means unknown — never report it as broken.
  2. request_link_recheck for anything the user wants re-tested now; report changes, not raw rows.

Fulfilment (seller)

  1. list_order_items — the flat queue of incomplete work across orders.
  2. draft_order_item — start an item and write its draft in one move. Declaring a link live stays human: it triggers the buyer's verify-and-release loop.
  3. Demand side: list_briefs with matchingMyInventory shows open buyer briefs your live listings could fill. Answering one is deliberately human — an agent that mass-answered briefs would be spam.

Safety & money

The safety model is encoded in the domain, not in prompt hopes: agents propose, humans pay. request_order creates a requested order that cannot cost anything until a person funds escrow in checkout; escrow releases per link only after the platform has fetched the page and verified the agreed link.

There is deliberately no tool that:

  • funds escrow, releases it, approves drafts for publication, or resolves disputes and refunds;
  • accepts or sends priced offers, or answers a brief;
  • subscribes, manages cards, or touches payout accounts;
  • provisions credentials — API keys, 2FA, passwords, company verification, or third-party metric keys;
  • writes a review — reputational statements stay human, though the reads for vetting are all there.

Where an agent produces something public under the user's name, the default is a draft: publish_article writes the words, a human decides whether they go out.