Skip to content
Docs
API Reference

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_id is optional. When you send it, it must equal client_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 503 with temporarily_unavailable means token issuance is not configured on the deployment. The API key header keeps working; check x-token-issuance in the authorization server metadata.

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.

ScopeGrants
organization:readRead the organization profile (name, contact details, website).
programs:readRead affiliate programs and their reward configuration.
affiliates:readRead 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

OperationoperationIdScope
GET /v1/organizationgetOrganizationorganization:read
GET /v1/programslistProgramsprograms:read
GET /v1/affiliateslistAffiliatesaffiliates:read
POST /oauth/tokencreateAccessTokennone

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 limitLimit
Per organization120 requests / 60s
Per IP, credential present120 requests / 60s
Per IP, no credential20 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 Deprecation and Sunset headers (RFC 8594) plus a Link with rel="successor-version", so an integration can detect its own obsolescence from any response.

Currently deprecated:

PathSuccessorStops answering
GET /organizationGET /v1/organization2027-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

ResourceURL
OpenAPI 3.0 documenthttps://api.viralref.com/openapi.json
MCP endpointhttps://api.viralref.com/mcp
MCP server cardhttps://api.viralref.com/.well-known/mcp/server-card.json
OAuth authorization server metadatahttps://api.viralref.com/.well-known/oauth-authorization-server
OAuth protected resource metadatahttps://api.viralref.com/.well-known/oauth-protected-resource
API catalog (RFC 9727)https://viralref.com/.well-known/api-catalog
Agent skills indexhttps://viralref.com/.well-known/agent-skills/index.json
LLM contexthttps://viralref.com/llms.txt and https://viralref.com/llms-full.txt
Agent instructionshttps://viralref.com/ai.txt

Webhooks are configured per organization in the dashboard and documented in API Keys & Webhooks.