ReplyNodes

Authentication

ReplyNodes has two first-class authentication options:

  • MCP OAuth — interactive MCP clients use Better Auth at https://auth.replynodes.com with the mcp:read scope.
  • API key — headless clients, CI, SDKs, and manual MCP configurations use an rn_test_* or rn_live_* key.

OAuth access is resolved to the authenticated ReplyNodes organization. Clients must not send an organization id, and API keys remain supported alongside OAuth. Sign in or manage access at https://platform.replynodes.com/sign-in and manage access at https://platform.replynodes.com/api-keys.

The canonical OpenAPI document defines HTTP Bearer authentication for the public API. Send the raw key after the Bearer scheme in the Authorization header. Key formats documented by the contract are rn_test_<64hex> and rn_live_<64hex>; never place a real key in a URL, browser bundle, prompt, log, or repository.

The gateway CLI reads FETCHER_API_KEY and constructs this header for requests. Other clients should use their secret-store equivalent and follow the same HTTP header contract.

See Quickstart for a request that fails closed when the environment variable is absent.

Agents

Start keyless: the capabilities listed in the Agent Quickstart work without a key up to their daily limits. Get a key only when a call returns 429 anonymous_limit_reached or 401; that response's error.next_action names the exact call (method, url, required_fields), a human_message for the human, and retry_after_seconds.

No browser is needed. The human only reads one 6-digit code from their inbox.

  1. Ask the human which email to use, then sign up. The response is immediate:

    curl -sS -X POST https://platform.replynodes.com/api/agent/signup \
      -H 'Content-Type: application/json' \
      -d '{"email":"you@example.com","agent_name":"my-agent"}'

    201 (or 200 when the same email signs up again) returns api_key (a restricted key, shown once), status: "restricted", expires_at (72 hours), verification (verify and resend endpoints, code_sent), human_message, and status_url. Show human_message to the human. Store api_key once as REPLYNODES_API_KEY; never print or log it. A restricted key already calls the keyless capabilities on its own daily allowance and never spends credits.

  2. When the human pastes the code, verify with the same key:

    curl -sS -X POST https://platform.replynodes.com/api/agent/verify \
      -H "Authorization: Bearer ${REPLYNODES_API_KEY}" \
      -H 'Content-Type: application/json' -d '{"code":"123456"}'

    200 returns status: "verified", the new expires_at (30 days), and workspace (created or existing: an email that already has an account attaches to that workspace). The key string does not change. Repeating verify is safe, including after a timeout.

  3. GET https://api.replynodes.com/v1/agent/status with the key returns its status, per-key quota (restricted) or credit balance, expiry, and next_actions with a human_message (verify, renew, add credits).

Codes are 6 digits, valid 10 minutes, 5 attempts; the newest code replaces older ones. Resend with POST https://platform.replynodes.com/api/agent/verify/resend and the same Bearer key (at most one code per minute and five per day per email). Renew a key before it expires by signing up again with the same email and verifying the new code.

When the workspace runs out of credits, credit-metered calls return HTTP 402 with code: "topup_required" and next_action.action: "top_up". Show its human_message: only the human can add credits, on the billing page in next_action.url. Retry once they confirm; do not retry in a loop.

HTTPerrorAgent action
400email_not_acceptedAsk for the human's real, non-disposable email.
400invalid_codeAsk the human to re-read the newest email (attempts_remaining).
400code_expired, code_attempts_exhaustedResend (next_action), then ask for the newest code.
401invalid_api_keyThe key is superseded or expired; sign up again with the same email.
403agent_key_not_permittedShow human_message: a workspace admin must allow agent keys.
409account_sign_in_requiredShow human_message: the human signs in once on the web with an email code.
410onboarding_expiredSign up again.
429rate_limited, resend_limitedWait Retry-After.
503email_signup_unavailableUse the device flow in next_action.
503temporarily_unavailableRepeat the same request after Retry-After.

On the API, a restricted key outside the keyless capabilities gets 403 verification_required, and a used-up per-key allowance gets 429 restricted_limit_reached; both carry next_action: verify_email.

Legacy device flow

Agents can still obtain a read-only API key through a short claim approved once by a human in a browser. Start a claim with:

curl -sS -X POST https://platform.replynodes.com/api/agent/claim \
  -H 'Content-Type: application/json' \
  -d '{"agent_name":"my-agent","agent_platform":"my-platform"}'

agent_name and agent_platform are optional labels. A successful response contains claim_id, device_code, user_code, verification_uri, verification_uri_complete, expires_in (900 seconds, or 15 minutes), interval (3 seconds), and docs. Give the human the exact verification_uri_complete link: it already includes the user_code. Wait for that one approval, then poll at the returned interval:

curl -sS -X POST https://platform.replynodes.com/api/agent/claim/token \
  -H 'Content-Type: application/json' \
  -d "{\"claim_id\":\"${CLAIM_ID}\",\"device_code\":\"${DEVICE_CODE}\"}"

On 200, store api_key once as REPLYNODES_API_KEY; never log it or ask the token endpoint for it again. The returned expires_at is authoritative. The default issued agent_read key lifetime is 30 days. If a later API call returns 401, start a new claim. The historical scope name is read:x_public; it means public provider reads and is not a request to rename the scope.

An agent key reaches only read-only provider GET and HEAD routes, /v1/capabilities, and the provider /v1/x surface where that surface is covered by provider-read routing. It cannot use non-GET methods or key, dashboard, internal, billing, wallet, checkout, webhooks, usage, overview, or me routes. Check /v1/capabilities for the current provider contract; this page does not promise PDF conversion or another route outside that allowlist.

Token polling outcomes

In this table, —/omitted status means the response body does not include the status field. The status is omitted on paths where the code does not return it, including some 503 temporarily_unavailable responses.

HTTPerrorstatusRetry-AfterAgent action
200—approved / state: revealed—Store api_key once with its expires_at; stop polling.
428authorization_pendingpending—Wait interval seconds, then poll again.
429poll_rate_limited—Returned headerWait for Retry-After; do not loop faster.
409already_delivereddelivered—Stop; the key was already revealed. Use the dashboard recovery details.
409already_delivereddelivery_uncertain—Do not start a new claim blindly; check with the human / Agent keys page; then start a new claim if the key was not stored.
410expired_tokenexpired when present—Stop and start a new claim.
403authorization_failedauthorization_failed when present—Stop; after human approval, restart the claim.
404invalid_claim——The claim id or device code is invalid; stop and start a new claim.
503temporarily_unavailabledelivery_uncertain when returned; omitted on some pathsReturned header when presentWait and retry while claim recovery remains possible.
503delivery_uncertain——Retry while claim recovery remains possible.
409delivery_uncertaindelivery_uncertain—Retries are exhausted; stop and use dashboard recovery.

For the complete protocol, use https://replynodes.com/auth.md.

On this page