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 URL | Issued with your API key at onboarding (deployment-specific) |
| Protocol | HTTPS, JSON only |
| Data direction | Read-only GETs — no publish, schedule, delete, or follow paths exist |
| Data scope | Public 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) orrn_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.
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
| HTTP | code | Meaning |
|---|---|---|
| 400 | invalid_request | Malformed input |
| 400 | invalid_cursor | Cursor unknown, expired, or tampered |
| 401 | invalid_or_expired_token | Key missing, unknown, expired, or revoked |
| 403 | forbidden_scope | Key lacks the required scope |
| 403 | not_entitled | Workspace plan lacks the capability |
| 404 | not_found | Resource does not exist or is not public |
| 405 | method_not_allowed | Non-GET on a data route |
| 429 | rate_limited | Quota exhausted; honor Retry-After |
| 502 | upstream_unavailable | Platform could not be reached from our adapter |
| 503 | degraded | Serving 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:
| Limit | Default |
|---|---|
| Per API key | 60 requests/min |
| Per organization | 300 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: trueis 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" }
}
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
| Operation | Params | Returns |
|---|---|---|
| app | id, country?, language? | Full public record for one app: title, description, icon URL, ratings. |
| search | term, country?, language?, limit? | Ranked apps matching a term; limit clamped server-side. |
| similar | id, 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.