API Reference
The ViralRef public API: authentication, scopes, endpoints, the error model, rate limits, versioning, and the MCP server for AI agents.
The ViralRef public API is a read-only REST API for your referral data. It is served from https://api.viralref.com and described by an OpenAPI 3.0 document at https://api.viralref.com/openapi.json.
Everything on this page is also available to agents as machine-readable resources: see MCP server below.
Base URL and versions
https://api.viralref.com/v1
Every operation lives under a major-version path prefix. See Versioning and deprecation for what we promise about changes.
Authentication
Two interchangeable credentials. Both are scoped to a single organization, and both are read-only.
API key
Create a key in the dashboard under Settings > Organization > Developers, then send it on every request:
export VIRALREF_API_KEY="api_..." # from the dashboard, shown once
curl https://api.viralref.com/v1/organization \
-H "X-API-Key: $VIRALREF_API_KEY"API keys are shown once at creation. Store them in environment variables, use a separate key per integration so you can revoke one without breaking the others, and never put one in client-side code.
OAuth
ViralRef supports the OAuth 2.0 client-credentials grant (RFC 6749, section 4.4) for clients and agents that prefer bearer tokens. The API key is the client credential.
Authorization server metadata is published at https://api.viralref.com/.well-known/oauth-authorization-server (RFC 8414), and protected-resource metadata at https://api.viralref.com/.well-known/oauth-protected-resource (RFC 9728).
Exchange a key for a token:
curl -X POST https://api.viralref.com/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_secret=$VIRALREF_API_KEY" \
-d "scope=organization:read programs:read"{
"access_token": "vrt_...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "organization:read programs:read"
}Then send it as a bearer token:
curl https://api.viralref.com/v1/programs \
-H "Authorization: Bearer $VIRALREF_ACCESS_TOKEN"Notes:
- Tokens last one hour and cannot be minted with a longer lifetime. Ask for a new one when it expires; there is no refresh token because minting a fresh token costs one request.
client_idis optional. When you send it, it must equalclient_secret-- the API key is both the identifier and the secret.- HTTP Basic works too: put the API key in the password position.
- Revoking the API key in the dashboard invalidates every token minted from it, immediately.
- There is no interactive authorization flow, so the metadata document declares no
authorization_endpoint. Client credentials is the only grant. - A
503withtemporarily_unavailablemeans token issuance is not configured on the deployment. The API key header keeps working; checkx-token-issuancein the authorization server metadata.
API keys are available on paid plans. Every ViralRef plan is paid -- there is no free tier.
Scopes
Each operation requires exactly one scope. A credential that presents a narrower set gets 403 with code: "insufficient_scope" and the required scope in the scope field.
| Scope | Grants |
|---|---|
organization:read | Read the organization profile (name, contact details, website). |
programs:read | Read affiliate programs and their reward configuration. |
affiliates:read | Read affiliates (referrers) and their status. |
Request a subset with the scope parameter when exchanging your key. Omit it and you receive every scope the key holds. The authoritative list is scopes_supported in the authorization server metadata.
Endpoints
| Operation | operationId | Scope |
|---|---|---|
GET /v1/organization | getOrganization | organization:read |
GET /v1/programs | listPrograms | programs:read |
GET /v1/affiliates | listAffiliates | affiliates:read |
POST /oauth/token | createAccessToken | none |
GET /v1/programs and GET /v1/affiliates accept limit (1-100, default 50). GET /v1/affiliates also accepts status (ACTIVE, PENDING, or BLOCKED).
Parameters are validated, not coerced: an out-of-range limit or an unrecognized status returns 400 with code: "invalid_request" rather than silently ignoring the filter and returning a wider result set. The MCP tools behave the same way, returning an error result.
List responses are wrapped:
{
"object": "list",
"data": [
/* ... */
]
}Affiliate contact details (email, phone) are deliberately not exposed by the API.
Errors
Every non-2xx response -- including a 404 for a path that does not exist -- is application/problem+json (RFC 9457). You never get an HTML error page.
{
"type": "https://viralref.com/docs/api-reference#error-unauthorized",
"title": "Unauthorized",
"status": 401,
"code": "unauthorized",
"detail": "The API key or bearer token is missing, malformed, or expired.",
"resolution": "Send a valid key as `X-API-Key: <key>`, or exchange it for a bearer token at POST /oauth/token.",
"instance": "/v1/organization",
"documentation_url": "https://viralref.com/docs/api-reference"
}Branch on code. It is stable. title, detail, and resolution are written for humans and may be reworded.
Error: invalid request
400 -- the request failed validation. Check the body, query parameters, and Content-Type against the OpenAPI document.
Error: unauthorized
401 -- the credential is missing, malformed, or expired. The WWW-Authenticate header names the protected-resource metadata document so a client can discover the token endpoint without reading these docs.
Error: insufficient scope
403 -- the credential is valid but lacks the scope the operation needs. The required scope is in the scope field of the response.
Error: not found
404 -- no resource exists at that path. The OpenAPI document lists every operation. Remember that paths are versioned: use /v1/....
Error: method not allowed
405 -- the path exists but not for that method. The Allow header lists the methods it accepts.
Error: unsupported media type
415 -- the request Content-Type is not supported. POST /oauth/token requires application/x-www-form-urlencoded.
Error: payload too large
413 -- the body exceeds the endpoint's limit. The MCP endpoint caps bodies at 512 KB and batches at 20 items.
Error: rate limited
429 -- the limit for your credential or IP is exhausted. Wait Retry-After seconds.
Error: internal error
500 -- an unexpected server-side failure. Retry with exponential backoff; if it persists, email support@viralref.com with the time of the request.
Rate limits
| Scope of limit | Limit |
|---|---|
| Per organization | 120 requests / 60s |
| Per IP, credential present | 120 requests / 60s |
| Per IP, no credential | 20 requests / 60s |
The organization limit is the one that normally binds. The per-IP buckets are separate, so anonymous traffic from a shared address cannot consume your organization's allowance. On the MCP endpoint each tools/call in a batch is charged separately, so a 20-item batch consumes 20 units.
Every response from an operation carries the RateLimit header fields, so you can self-throttle without waiting for a 429:
RateLimit-Limit: 120
RateLimit-Remaining: 118
RateLimit-Reset: 60
RateLimit: limit=120, remaining=118, reset=60
RateLimit-Policy: "authenticated-organization"; q=120; w=60
A 429 adds Retry-After with the same number of seconds.
Versioning and deprecation
- Operations live under a major-version path prefix (
/v1). Additive, backwards-compatible changes ship inside the current major version, so new response fields can appear without notice -- ignore fields you do not recognize. - A breaking change ships under a new prefix (
/v2). The previous prefix keeps working for at least 6 months. - A path scheduled for removal answers with
DeprecationandSunsetheaders (RFC 8594) plus aLinkwithrel="successor-version", so an integration can detect its own obsolescence from any response.
Currently deprecated:
| Path | Successor | Stops answering |
|---|---|---|
GET /organization | GET /v1/organization | 2027-03-01 |
MCP server
ViralRef runs a Model Context Protocol server at https://api.viralref.com/mcp over the Streamable HTTP transport. It exposes the same read-only data as tools, plus documentation resources.
Discovery needs no credential -- initialize, tools/list, resources/list, and resources/read all answer anonymously, so an agent can inspect the server before asking anyone for a key. Only tools/call requires authentication, with the same API key or bearer token as the REST API.
curl -X POST https://api.viralref.com/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"my-agent","version":"1.0"}}}'Tools: get_organization, list_programs, list_affiliates. All are read-only and annotated as such.
Resources: viralref://api/reference.md, viralref://api/errors.md, viralref://api/scopes.md, viralref://api/openapi.json, viralref://product/overview.md.
The server card is published at https://api.viralref.com/.well-known/mcp/server-card.json.
Machine-readable index
| Resource | URL |
|---|---|
| OpenAPI 3.0 document | https://api.viralref.com/openapi.json |
| MCP endpoint | https://api.viralref.com/mcp |
| MCP server card | https://api.viralref.com/.well-known/mcp/server-card.json |
| OAuth authorization server metadata | https://api.viralref.com/.well-known/oauth-authorization-server |
| OAuth protected resource metadata | https://api.viralref.com/.well-known/oauth-protected-resource |
| API catalog (RFC 9727) | https://viralref.com/.well-known/api-catalog |
| Agent skills index | https://viralref.com/.well-known/agent-skills/index.json |
| LLM context | https://viralref.com/llms.txt and https://viralref.com/llms-full.txt |
| Agent instructions | https://viralref.com/ai.txt |
Webhooks are configured per organization in the dashboard and documented in API Keys & Webhooks.