MCP server for AI agents
Point any MCP client at https://viralpayouts.com/api/mcp with a ViralPayouts key as a bearer token, or connect Claude or ChatGPT by signing in (OAuth, no key). A brand key (vpk_) gets 43 tools to run programs, partners, sales and payouts. A partner key (vpp_) gets 21 tools for that partner's programs, links, stats and earnings.
Connect
The server speaks MCP over streamable HTTP: JSON-RPC 2.0 POSTs to one URL, answered with JSON, no session to keep. It authenticates with a key in the Authorization header, so your client must be able to send a header. Create the key first: a brand owner in the console (Integration tab, API keys), a partner in the portal (Your API keys). What each key and role can do.
claude mcp add --transport http viralpayouts https://viralpayouts.com/api/mcp \
--header "Authorization: Bearer vpk_..."{
"mcpServers": {
"viralpayouts": {
"url": "https://viralpayouts.com/api/mcp",
"headers": { "Authorization": "Bearer ${env:VIRALPAYOUTS_KEY}" }
}
}
}{
"mcpServers": {
"viralpayouts": {
"command": "npx",
"args": ["mcp-remote", "https://viralpayouts.com/api/mcp", "--header", "Authorization:${AUTH_HEADER}"],
"env": { "AUTH_HEADER": "Bearer vpk_..." }
}
}
}Apps that connect with a sign-in (Claude custom connectors, ChatGPT and other OAuth clients) need no key: see Connect from Claude or ChatGPT.
Agents can find the server at /.well-known/mcp.json, which also points to the OpenAPI document.
Connect from Claude or ChatGPT (sign in, no key)
Claude, ChatGPT and other MCP clients that connect with a sign-in can use this server without an API key. Give the app the server URL https://viralpayouts.com/api/mcp. The app registers itself, sends you to ViralPayouts to sign in and approve, and gets its own access, which you can disconnect at any time. Nothing has to be set up on the ViralPayouts side first.
| Step | In Claude (claude.ai, Desktop, mobile) | In ChatGPT |
|---|---|---|
| 1. Add the server | Customize, Connectors, Add custom connector. On a Team or Enterprise plan an Owner adds it under Organization settings, Connectors, Add, Custom. | Open chatgpt.com/plugins, press +, then Add custom MCP server. Your workspace may need developer mode turned on by an admin. |
| 2. Enter the URL | Name it ViralPayouts and enter https://viralpayouts.com/api/mcp. Leave the OAuth client ID and secret empty. | Enter a name and https://viralpayouts.com/api/mcp. Choose OAuth as the authentication, accept the warning and create it. |
| 3. Sign in | Press Connect. Claude opens ViralPayouts. | ChatGPT opens ViralPayouts when you connect. |
| 4. Approve | Sign in as a brand (email and password) or as a partner (a one-time link sent to your email). Choose the account and the access, then Approve. You go back to Claude. | The same page: choose the account and the access, then Approve. You go back to ChatGPT. |
What the consent page shows: the app's name, the website it will send you back to, and the accounts you can give it. A brand member chooses one brand and a role no higher than their own (viewer, manager or owner); a partner chooses read or write. The app then has exactly the tools an API key with that role or scope has. It can never change a payout account or tax form, and it stops working if you leave the brand's team.
Disconnect an app in the brand console (Integration tab, Connected apps) or in the partner portal (Connected apps). In Claude Code: claude mcp add --transport http viralpayouts https://viralpayouts.com/api/mcp, then run /mcp to sign in.
| For client developers | Value |
|---|---|
| Protected resource metadata (RFC 9728) | https://viralpayouts.com/.well-known/oauth-protected-resource |
| Authorization server metadata (RFC 8414) | https://viralpayouts.com/.well-known/oauth-authorization-server |
| Client registration | Dynamic client registration (RFC 7591) at /oauth/register, or a Client ID Metadata Document (an https client_id). Public clients; redirect URIs must be https, or http on localhost or 127.0.0.1 (any port). |
| Flow | Authorization code with PKCE (S256 only) and the resource parameter (RFC 8707). Responses carry iss (RFC 9207). |
| Scopes | read, write (offline_access accepted). The person can grant less on the consent page. |
| Tokens | Access tokens last 1 hour and work only for the resource they were issued for (/api/mcp or /api/v1). Refresh tokens rotate on every use; reusing an old one disconnects the app. Revocation (RFC 7009) at /oauth/revoke. |
How the tools behave
| Rule | What it means |
|---|---|
| Same rules as the console | A tool acts with the key's brand and role (or the partner's account and scope) and calls the same functions as the console and portal, after the same ownership checks. An agent can do nothing a person with that role could not. |
| Same answers as the REST API | Every tool beyond the original ten runs its REST endpoint through the same code, so its result is the REST answer: { data } or, for lists, { data, has_more, next_cursor }. |
| Errors say the next step | A failed call is a tool result with isError: true, the message, and "Next step: ...": which tool to call, which field to fix, or which key to ask for. |
| Money is in cents | Amounts are in minor units of the program currency unless a field says otherwise (send_test_sale takes amount in major units). |
| Retries are safe | refund_conversion needs an idempotencyKey; send_message, broadcast_message, join_program, send_my_message accept one. The same key returns the first answer instead of running twice. |
| Limits | 120 requests a minute per key; up to 20 requests in one JSON-RPC batch. |
curl https://viralpayouts.com/api/mcp \
-H "Authorization: Bearer vpk_..." -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_programs","arguments":{}}}'Tools for a brand key (43)
The first 13 are the original agent tools. The rest each match one REST endpoint. “Needs” is the least role the key must have.
| Tool | What it does | Needs | REST endpoint |
|---|---|---|---|
list_programs | Lists this brand's partner programs with their ids, status, commission and the pages partners apply on. | Viewer | Original tool |
create_program | Creates a partner program. Needs a name and a destinationUrl; everything else has a sensible default. Returns the program with its id, then call get_integration to connect the brand's checkout. | Owner | Original tool |
update_program | Changes a program. Send programId and only the fields to change, for example {"programId": "...", "status": "live"}. On a live program with approved partners, a cut takes effect 3 business days later (see scheduledChange in the answer) and an increase applies at once; partners are emailed either way. A program with no partners changes at once. | Owner | Original tool |
get_integration | How the brand's site or Stripe reports sales for one program: the signed event API and the Stripe webhook URL. Owner keys also get the signing secret. | Viewer | Original tool |
send_test_sale | Runs a test sale through the real pipeline for one partner of a program, to check tracking end to end. A test sale is marked as a test and never becomes payable. | Manager | Original tool |
get_program_stats | One program's results: clicks, sales, revenue, commission, fee, ROAS, earnings per click, tracking health and whether its balance covers the next 7 days of payouts. Money is in minor units (cents). | Viewer | Original tool |
list_partners | The partners of one program with their status, clicks, sales, revenue, commission and ROAS over a period. Money is in minor units (cents). | Viewer | Original tool |
get_partner_stats | One partner's results in a program over a period, with their best sub IDs. Money is in minor units (cents). | Viewer | Original tool |
decide_partner | Approves, rejects, suspends or reinstates a partner, or warns them about a minor breach of the program terms (they get 7 days to fix it) and clears the warning. A rejection, suspension or warning needs a reason, which the partner sees. | Manager | Original tool |
decide_conversion | Approves or rejects a conversion (a sale credited to a partner). A rejection needs a reason, which the partner sees, and a reasonCode from the program terms. Once a commission is past its payment date it can only be rejected for fraud. | Manager | Original tool |
get_referral_link | Builds an AI-resilient tracked referral URL, partner code, signed attribution token (vp_tok_...) and protocol objects (ACP affiliate_attribution and UCP attribution) for a partner in one of this brand's programs. | Viewer | Original tool |
create_checkout_link | Embeds a partner's referral parameters (ref, attribution/ref) and a signed attribution token (vp_tok_...) into a cart or checkout URL, and returns the ACP affiliate_attribution and UCP attribution objects. | Viewer | Original tool |
log_agent_referral | Records an agent-tagged referral touch for a partner in this brand's program so an AI assistant or shopping agent can log discovery credit without overwriting an earlier unexpired human click. | Viewer | Original tool |
whoami | Which brand this key acts for, its role, and the network. A cheap first call to check a key works. | Viewer | GET /me |
get_program | One program with its terms, its machine-readable rates (basis points and cents) and its product rates. | Viewer | GET /programs/{programId} |
get_program_breakdown | Clicks, sales, sales value and commission grouped by the visitor's country or device. A sale with no click (coupon or referral code) is grouped as not known. | Viewer | GET /programs/{programId}/breakdown |
get_funding | Money paid in for this program and what is left, whether it covers the next 7 days of payouts, the next payout day, and the program's invoices. | Viewer | GET /programs/{programId}/funding |
list_events | The sale and refund events this program received (event API, Stripe, Shopify, console), newest first, each with what happened to it: processed, duplicate, unmatched or error, and why. | Viewer | GET /programs/{programId}/events |
browse_partners | The partners of one program, newest first, with status, contact, clicks, customers, recruits, payout readiness and balance (cents). For results over a period use the stats endpoint. | Viewer | GET /programs/{programId}/partners |
get_partner | One partner: status and reason, application, terms accepted, payment schedule, any warning, payout readiness and balance (cents). | Viewer | GET /partners/{partnerId} |
set_partner_payment_schedule | A payment schedule agreed with this one partner: they are paid this many days after each sale (0 to 30) instead of the program's. null goes back to the program's. Commission rates are set per program and per product, not per partner. | Owner | PATCH /partners/{partnerId} |
get_partner_links | The partner's customer link, recruit link, their links from before handles (which keep working) and their coupon code, if the program has coupons. | Viewer | GET /partners/{partnerId}/links |
get_partner_sub_ids | Clicks, sales, sales value, commission earned and EPC grouped by one of the partner's sub IDs (sub1 to sub5). | Viewer | GET /partners/{partnerId}/sub-ids |
get_partner_recruits | The partners this partner recruited into the program, whether each is active, and the recruiter override this partner has earned on each (cents). | Viewer | GET /partners/{partnerId}/recruits |
list_messages | The latest messages between the brand and one partner, oldest first. Reading marks the partner's messages read. | Viewer | GET /partners/{partnerId}/messages |
send_message | Sends a message to one partner. They see it in their portal and are emailed. | Manager | POST /partners/{partnerId}/messages |
broadcast_message | Sends one message to every approved partner of a program. Up to 10 broadcasts an hour per brand. | Manager | POST /programs/{programId}/messages |
get_rates | What partners earn on this program: the commission, the recruiter override (the second tier) with its base and period, and any product rates and app-event bounties. | Viewer | GET /programs/{programId}/rates |
set_rate_rules | Replaces the program's product rates (a different commission for a product_id or plan) and app-event bounties (a fixed amount per signup, install...). On a live program with approved partners a cut takes effect 3 business days later (scheduledFor in the answer) and an increase at once; every partner is emailed either way. A change starts a new terms version when it applies. The program's own commission and recruiter override are changed with PATCH /programs/{programId}. | Owner | PUT /programs/{programId}/rates |
list_recruiter_overrides | Every partner of the program who recruited someone: how many recruits (and how many approved), and the recruiter override they earned on recruits' sales in the period, approved and pending (cents, after refunds). Test sales are left out. | Viewer | GET /programs/{programId}/recruiter-overrides |
list_clicks | Counted clicks on the program's partner links, newest first: partner, country, device, referrer, landing page and sub IDs. Bots, previews and repeats are filtered out before they are counted. | Viewer | GET /programs/{programId}/clicks |
list_conversions | Sales and app events credited to partners, newest first, with the commission, override and fee on each (cents, after refunds). | Viewer | GET /programs/{programId}/conversions |
get_conversion | One conversion with its attribution, sub IDs, coupon, product, hold date and the money on it. | Viewer | GET /conversions/{conversionId} |
refund_conversion | Records a refund of the order behind a conversion, exactly as a refund event from the signed event API: commission, override and fee are reversed in proportion. Send amountCents (this refund) or refundedTotalCents (everything refunded so far). Leave both out for a full refund. A refund after the partner was paid is recovered from their next commissions. Needs an Idempotency-Key. | Owner | POST /conversions/{conversionId}/refund |
list_ledger | Every money entry of the program, newest first. The ledger is append-only: a correction is a new entry with the opposite sign. kind is direct (commission), override (recruiter) or platform_fee; entry is accrual, reversal, payout or payout_reversal. Cents. | Viewer | GET /programs/{programId}/ledger |
list_balances | Per partner: pending (awaiting approval), in hold (approved, before its payment date), payable, being paid, paid, and earned this year. Cents; test sales left out. | Viewer | GET /programs/{programId}/balances |
list_payouts | Payouts to partners, newest first: amount, method (whop or manual bank transfer), status (pending, paid, failed, held) and where a rail payout stands. | Viewer | GET /programs/{programId}/payouts |
get_payout | One payout. | Viewer | GET /payouts/{payoutId} |
list_payout_batches | Payout runs of the program, newest first, each with its total and what happened to its payouts: sent, sending, needing attention, by bank transfer or held. | Viewer | GET /programs/{programId}/payout-batches |
get_payout_batch | One payout run with its summary and its payouts (up to 500). | Viewer | GET /payout-batches/{batchId} |
get_webhook_settings | Where sales reach this program (the signed event API, the Stripe and Shopify webhook URLs) and whether each Stripe or Shopify signing secret is set. Secrets are write-only: only their last 4 characters come back. | Viewer | GET /programs/{programId}/webhooks |
set_stripe_webhook_secret | Stores the signing secret (whsec_...) of the Stripe webhook endpoint you pointed at this program, so its sales are verified. Send an empty string to clear it. | Owner | PUT /programs/{programId}/webhooks/stripe |
set_shopify_webhook_secret | Stores the Shopify webhook signing secret for this program's order webhooks. Send an empty string to clear it. | Owner | PUT /programs/{programId}/webhooks/shopify |
Tools for a partner key (21)
A partner key sees only these. “Needs” is the key's scope: read, or write for tools that change something.
| Tool | What it does | Needs | REST endpoint |
|---|---|---|---|
get_my_account | Your account (the person across every program), your public page and the key making the call. | Read | GET /partner/me |
list_my_programs | Every program you have joined or applied to, with your membership status and the program's. | Read | GET /partner/programs |
get_my_program | Your membership of one program: its terms, your links and coupon, your balance (cents) and why it is not paid yet if it is not. | Read | GET /partner/programs/{program} |
get_my_links | Your customer link, your recruit link (people who join through it are your recruits and earn you the override) and your coupon code. | Read | GET /partner/programs/{program}/links |
build_link | Builds your customer link with sub IDs (sub1 to sub5, up to 80 characters each) and an optional deep link to a page on the brand's own site. Sub IDs are kept with each click and sale, and appear in your stats and postbacks. Nothing is stored: a link is your link plus these parameters, so you can also build it yourself. | Read | POST /partner/programs/{program}/links |
get_my_stats | Your clicks, sales, sales value, commission earned and EPC in one program, grouped by one sub ID, with totals. Cents. | Read | GET /partner/programs/{program}/stats |
get_my_breakdown | Your clicks, sales and commission in one program grouped by the visitor's country or device. | Read | GET /partner/programs/{program}/breakdown |
list_my_conversions | Your sales in one program and your recruits' sales (where you earn the override), newest first, with what you earned on each. On a recruit's sale you see the outcome and your earning, never the customer. | Read | GET /partner/programs/{program}/conversions |
list_my_payouts | Payouts to you from one program, newest first. | Read | GET /partner/programs/{program}/payouts |
get_my_earnings | Your balance in every program (pending, in hold, payable, being paid, paid; cents), totals per currency, and what you earned this year across all programs. | Read | GET /partner/earnings |
list_my_recruits | The partners you recruited into one program, whether each is active, and the override you earned on each (cents), with the total. | Read | GET /partner/programs/{program}/recruits |
search_marketplace | The public directory: live programs of brands ViralPayouts has activated. Matches q against the name, description and brand. Shows whether you are already in each. | Read | GET /partner/marketplace |
join_program | Applies to a program as you. An open program approves you at once (unless a risk check holds the application for review); otherwise the brand reviews it. You must accept the program terms (read them at the terms URL first). | Write | POST /partner/marketplace/{program}/join |
get_postback | The URL ViralPayouts calls when one of your sales is recorded, approved or reversed in this program, the macros it can carry, and the latest deliveries. | Read | GET /partner/programs/{program}/postback |
set_postback | Sets or clears (null) the postback URL for one program. Use macros such as {click_id}, {payout} and {status}. | Write | PUT /partner/programs/{program}/postback |
test_postback | Calls your postback URL once with sample values and returns what happened. Up to 10 an hour per program. | Write | POST /partner/programs/{program}/postback/test |
list_my_messages | The latest messages between you and the brand of one program, oldest first. Reading marks the brand's messages read. | Read | GET /partner/programs/{program}/messages |
send_my_message | Sends a message to the brand of one of your programs. Up to 20 an hour per program. | Write | POST /partner/programs/{program}/messages |
get_my_profile | How you promote (your words, main and other methods, paid-search answer, the promise to label posts as ads) and the places you promote from, each with whether ViralPayouts verified it, how, and the follower count when one was fetched. Brands see this when you apply. | Read | GET /partner/profile |
update_my_profile | Saves how you promote. promoText (at least 40 characters) and primaryMethod are required; methods are keys from the list in the docs (content_review, social_organic, newsletter_email, paid_search_brand ...). Fields you leave out keep their value. | Write | PUT /partner/profile |
list_my_properties | Your websites, newsletters and social accounts, with verification status, method, last check and follower counts as fetched (null when not fetched). To verify one, use the partner portal. | Read | GET /partner/properties |