Documentation

API Reference

Everything an agent needs to consume the ReplyNodes read API: auth, envelope, errors, pagination, and the operations available on each live provider today.

Overview

ReplyNodes exposes public platform data as normalized JSON through one interface. Every provider speaks the same contract — same envelope, same error codes, same pagination semantics — so an agent that integrates one provider integrates all of them.

Base URLIssued with your API key at onboarding (deployment-specific)
ProtocolHTTPS, JSON only
Data directionRead-only GETs — no publish, schedule, delete, or follow paths exist
Data scopePublic platform data only; no authenticated-as-user access anywhere

Authentication

Send your key as a Bearer token on every data request:

Authorization: Bearer rn_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • Keys look like rn_test_... (sandbox) or rn_live_... (production).
  • Each key carries scopes; current scope: read:x_public.
  • Keys are stored server-side only as SHA-256 hashes — shown once at mint time.
A malformed-format key fails fast with 401 invalid_or_expired_token. If you get 401 on a key you believe is valid, it was rotated or revoked — mint a new one.

Response envelope

Every success response has the shape:

{
  "data": { ... },                       // endpoint payload
  "meta": {
    "request_id": "req-a1b2c3d4",        // always present
    "next_cursor": "...",                // present when more pages exist
    "stale": true                        // only on degraded cache-fallback responses
  }
}

Every non-2xx response has the shape:

{
  "error": {
    "code": "not_found",
    "message": "Human-readable detail.",
    "request_id": "req-a1b2c3d4"
  }
}

The HTTP status mirrors the outcome; the error.code gives agents a stable string to branch on.

Error codes

HTTPcodeMeaning
400invalid_requestMalformed input
400invalid_cursorCursor unknown, expired, or tampered
401invalid_or_expired_tokenKey missing, unknown, expired, or revoked
403forbidden_scopeKey lacks the required scope
403not_entitledWorkspace plan lacks the capability
404not_foundResource does not exist or is not public
405method_not_allowedNon-GET on a data route
429rate_limitedQuota exhausted; honor Retry-After
502upstream_unavailablePlatform could not be reached from our adapter
503degradedServing stale cache only during an upstream outage

Pagination

List endpoints return opaque cursors. Pass next_cursor back verbatim:

GET /v1/x/users/{handle}/posts?cursor=<next_cursor>
  • null next_cursor = end of collection.
  • Cursors encode position only — no filters, tenant data, or raw offsets.
  • Tampered cursors fail closed (400 invalid_cursor).
  • Cursors expire when upstream pages rotate — restart from page one.

Rate limits

Fixed-window counters per minute, enforced per key and per organization before any upstream work happens:

LimitDefault
Per API key60 requests/min
Per organization300 requests/min

Over-limit responses carry Retry-After plus X-RateLimit-Limit / X-RateLimit-Remaining headers. Well-behaved agents should read X-RateLimit-Remaining and back off before hitting the wall.

Caching

Public reads go through a short-lived shared cache. Responses carry X-Cache: hit | miss | stale:

  • hit — served from cache, no upstream call made.
  • miss — fetched fresh from the platform.
  • stale — warm-but-expired copy served during an upstream outage; meta.stale: true is set. Treat such payloads as potentially outdated.

Provider: X (Twitter)

Scope required: read:x_public. All routes are GET.

GET /v1/x/capabilities  — unauthenticated

Returns the implemented route table and live provider status, including circuit state. Point agents here first instead of hard-coding routes.

GET /v1/x/users/{handle}/posts

A page of public posts by an account, newest first.

curl -H "Authorization: Bearer $KEY" \
  "$BASE/v1/x/users/elonmusk/posts?cursor=<next_cursor>"

data is a post_page: normalized posts with inner availability metadata and next_cursor.

GET /v1/x/posts/{post_id}

A single public post by numeric ID. Returns the normalized post shape: platform-prefixed URN id, author object, text, RFC3339 timestamps, metrics with explicit nulls, media array.

{
  "data": {
    "id": "x:post:1789400000000000001",
    "platform": "x",
    "author": { "id": "x:user:1234567890", "handle": "@example", ... },
    "text": "...",
    "created_at": "2026-08-01T12:00:00Z",
    "metrics": { "likes": 10, "reposts": 2, "views": null },
    "media": [ { "type": "image", "url": "https://...", ... } ]
  },
  "meta": { "request_id": "req-a1b2c3d4" }
}
Counts are integers or explicit null — never fabricated zeros. Branch on null, not on zero, when checking "unknown metric".

Provider: Google Play / App Store

Served through a sandboxed provider runtime behind the gateway. Application outcomes answer HTTP 200 with an envelope whose ok flag discriminates success from failure:

{ "ok": true,  "data": { ... } }
{ "ok": false, "error": { "code": "unsupported_operation", "message": "..." } }

Operations

OperationParamsReturns
appid, country?, language?Full public record for one app: title, description, icon URL, ratings.
searchterm, country?, language?, limit?Ranked apps matching a term; limit clamped server-side.
similarid, country?, language?Public related-apps listing for one app.

Numeric track IDs are carried as strings to avoid precision loss in JS-based agent runtimes. Bundle IDs (com.microsoft.to-do) are accepted wherever a track ID is. Deferred operations (list, developer, reviews, …) are enumerated explicitly so agents can discover the boundary without trial-and-error.

Request IDs

Send X-Request-Id on requests to correlate logs across your system and ours; the value is echoed as meta.request_id (or generated when absent). Always include it in support requests.