RegionHopAPI referenceNetwork status ↗

THE REGIONAL API RELAY

Your request.
From somewhere else.

Put RegionHop in front of an API URL to send the same request from another location. Keep the response intact, or capture a report with location and timing details.

One key to get started

Sign in with your invited email address and create a personal API key. Set it in your terminal before running these examples. The documentation is public; API requests require authentication.

Terminal
export REGIONHOP_KEY='YOUR_REGIONHOP_KEY'

Use X-RegionHop-Key for the proxy and Authorization: Bearer for probe and catalog endpoints. Keep your target API token separate. Personal keys allow proxy, probe, and catalog reads. Catalog changes require the administrator key.

Each account allows 120 authenticated API requests per minute and 10,000 per UTC day across all its keys. A limit returns HTTP 429 with Retry-After. Manage expiry and revoke keys from your account page. You can have up to 10 active keys.

01 / PROXY

Add a prefix. Keep your request.

Prepend https://regionhop.com/{destination}/ to the complete target URL. Send its usual method, headers, and body. Target query parameters stay in the target URL; they are not RegionHop options.

METHOD/{destination}/https://api.example.com/path?query=value
POST through San Jose (SJC)
curl --include 'https://regionhop.com/SJC/https://httpbingo.org/anything' \
  -H "X-RegionHop-Key: $REGIONHOP_KEY" \
  -H 'Content-Type: application/json' \
  --data-binary '{"hello":"world"}'

This example really sends a POST to an echo API. Substitute your own target URL and body. For a file, use --data-binary @payload.json. Add -H 'Authorization: Bearer YOUR_TARGET_TOKEN' when your target requires it.

DestinationValue in the URLBehavior
Observed coloSJC, CDG, or another cataloged uppercase codeSelect a catalog node and verify its observed colo before sending.
Region hintwnam, weur, or another supported hintUse a reusable instance with best-effort regional placement.
Specific nodenode-{id}Use an active 64-character lowercase hexadecimal ID from GET /nodes. Verify its last known colo before sending.

Methods: GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS. For GET, omit the data argument. For HEAD, use curl --head.

The response stays the target response

The target HTTP status, application headers, and body pass through without a JSON wrapper. Binary responses and streams are supported. RegionHop adds metadata headers:

Illustrative response
HTTP/1.1 200 OK
Content-Type: application/json
X-RegionHop-Colo: SJC
X-RegionHop-Requested-Colo: SJC
X-RegionHop-Headers-Ms: 42
X-RegionHop-Dispatch-Ms: 190
X-RegionHop-Upstream-Status: 200

{"hello":"world"}
Authentication in the URL

Clients that cannot add headers can use /{destination}/{key}/https://target.example/path. URL-encode the key as one path segment. The URL key takes precedence over X-RegionHop-Key. A URL containing a key is a credential and can appear in logs and browser history. Prefer the header form when possible.

Transparent at the API level: connection-specific headers, forwarding headers, and Referer are removed; Host and Content-Length are runtime-managed. The X-RegionHop-* namespace is reserved. HTTP framing and compression can be managed by the runtime.

02 / PROBE

Get a report around the response.

POST/probe

Send JSON with Content-Type: application/json. Use exactly one destination selector: region, colo, or node.

Probe from San Jose (SJC)
curl 'https://regionhop.com/probe' \
  -H "Authorization: Bearer $REGIONHOP_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
    "url": "https://httpbingo.org/anything",
    "colo": "SJC",
    "method": "POST",
    "headers": {"User-Agent": "RegionHop-Docs/1.0"},
    "payload": {"hello":"world"}
  }'
ParameterValues and default
url requiredAbsolute HTTP(S) URL with a public DNS hostname. No URL credentials, local hostnames, or IP literals.
regionOne of the 11 lowercase region hints. Exactly one selector required.
coloThree uppercase letters from the catalog, for example SJC. Exactly one selector required.
nodeActive 64-character lowercase hexadecimal ID from GET /nodes. Exactly one selector required.
methodGET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS. Default: POST.
headersObject whose values are strings. Only these target headers are forwarded. Default: none. Include the target Authorization here if needed.
payloadOptional JSON value. Strings are sent verbatim; other values are JSON-encoded. Omit for GET and HEAD. Content-Type defaults to text/plain for strings, application/json otherwise, unless supplied in headers.
timeoutMsInteger 100 to 30000. Default: 15000. Covers target fetch and reading the response, excluding the preceding location check.
maxResponseBytesInteger 1 to 5242880. Default: 1048576 (1 MiB). Larger responses are captured up to this limit.

The example supplies a User-Agent for the echo service. Probe mode does not copy the caller's headers to the target.

Managed headers are rejected in probe arguments: Host, Content-Length, connection and proxy headers, Forwarded, Via, X-Real-IP, True-Client-IP, CF-*, X-Forwarded-*, X-RegionHop-*, and the internal hop marker.

Illustrative report using a colo selector
{
  "objectId": "<catalog node ID>",
  "startedAt": "2026-09-18T10:00:00.000Z",
  "requestedColo": "SJC",
  "location": {
    "colo": "SJC",
    "source": "cloudflare-trace",
    "observedAt": "2026-09-18T09:59:59.990Z",
    "error": null
  },
  "timings": {
    "headersMs": 42,
    "durationMs": 48,
    "dispatchMs": 190
  },
  "response": {
    "status": 200,
    "statusText": "OK",
    "ok": true,
    "headers": {
      "content-type": "application/json"
    },
    "body": {
      "hello": "world"
    },
    "bodyEncoding": "json",
    "bytes": 17,
    "truncated": false
  },
  "error": null,
  "ingressColo": "FRA"
}

Reading a report

  • location.colo is a fresh outbound trace observation. ingressColo is where your client entered Cloudflare.
  • objectId identifies the instance. requestedColo appears for strict colo/node selections. region appears when the instance has a regional hint, which may differ from its observed location.
  • headersMs measures the target fetch until headers arrive. durationMs includes reading the captured body. dispatchMs includes node selection, startup, the location check, target fetch, encoding, and dispatch overhead. None includes the client's trip to RegionHop.
  • response.bodyEncoding is json, UTF-8 text, or base64 for binary/unknown content types. Truncated JSON is returned as text. bytes is the captured byte count; truncated says whether capture hit the size limit.
  • Captured headers are diagnostic metadata. The runtime can decompress the body, so do not use those headers to decode the report again.

A completed probe returns HTTP 200 even when the target returns 4xx/5xx or the report contains a target timeout. Check both error and response.status. Authentication, validation, missing destinations, and dispatch failures use HTTP error statuses instead.

03 / LOCATIONS

Choose where the request starts.

Use an uppercase colo for a verified catalog selection. RegionHop checks the node before sending and does not silently fall back to another colo or retry the target request.

Observed colos

Loading the latest catalog health. You can also view the status page.

Location chips copy a proxy prefix. Checks run hourly and become stale after 90 minutes. Health describes our nodes reaching the trace endpoint, not the availability of your API.

Region hints

These are placement preferences, not exact city selectors. Hints can resolve to the same colo or a nearby supported region. For example, use /weur/https://your-api.example/path or "region": "weur".

HintRequested region
wnamWestern North America
enamEastern North America
weurWestern Europe
eeurEastern Europe
apacAsia-Pacific
apac-neNortheast Asia-Pacific
apac-seSoutheast Asia-Pacific
ocOceania
samSouth America (may use a nearby supported region)
afrAfrica (may use a nearby supported region)
meMiddle East (may use a nearby supported region)

The reported colo comes from a separate request to Cloudflare's trace endpoint. It is not an authoritative physical-location reading or proof of the target's exact network egress. To verify what your own API sees, return its observed source IP or request metadata.

04 / METADATA

Inspect the route and timing.

Proxy metadata is added to response headers when available. Target 4xx/5xx responses remain target responses and do not gain a RegionHop error code.

Response headerMeaning
X-RegionHop-ColoFresh trace-observed colo. Omitted if unavailable on a best-effort hint route.
X-RegionHop-Requested-ColoExpected colo for a strict colo or node selection.
X-RegionHop-NodeSelected Durable Object instance ID.
X-RegionHop-RegionThe instance’s original regional hint. Omitted for unhinted instances.
X-RegionHop-Observed-AtISO timestamp of the successful location observation.
X-RegionHop-Ingress-ColoWhere the client entered Cloudflare.
X-RegionHop-Headers-MsTarget fetch to response headers in milliseconds, excluding the preceding trace check.
X-RegionHop-Dispatch-MsNode selection and Worker-to-node dispatch through response headers, including startup and location verification. Excludes client network time and body download.
X-RegionHop-Upstream-StatusTarget HTTP status, also used as the actual proxy response status.
X-RegionHop-ErrorRegionHop failure code. Absent for ordinary target responses.

What the target receives

Proxy mode adds X-RegionHop-Node, X-RegionHop-Colo when observed, and X-RegionHop-Region when the instance has a hint. Both modes add the internal X-Regional-Probe-Hop: 1 marker to prevent recursive relaying. RegionHop strips its proxy credentials; target Authorization is forwarded. Probe mode forwards only the target headers supplied in the JSON envelope, plus the hop marker.

Use probe mode for captured-body duration. A streaming proxy cannot report total download time in headers that have already been sent.

05 / BEHAVIOR

Know what happened.

Proxy failures return plain text with X-RegionHop-Error. Probe failures before dispatch return JSON shaped as {"error":"message"}. Once a probe report is available, failures use error: {code, message} with response: null.

Condition / codeProxy HTTP statusProbe behavior
UNAUTHORIZED: missing or incorrect key401401, JSON error string.
INVALID_REQUEST: malformed arguments or managed headers400; 413 for oversized input; 403 for a configured hostname restrictionSame statuses, JSON error string. Non-JSON /probe input returns 415.
DESTINATION_UNAVAILABLE: no active matching node503503, JSON error string. Target not sent.
LOCATION_UNAVAILABLE: strict location cannot be checked503Report error when pre-send trace fails; HTTP 503 if the selected node has no known colo. Target not sent.
COLO_MISMATCH: strict trace differs from expected colo409HTTP 200 report with this error. Target not sent.
UPSTREAM_TIMEOUT: target exceeds deadline504HTTP 200 report with this error. The target may have processed the request.
UPSTREAM_FETCH_FAILED: target connection fails502HTTP 200 report with this error; also covers response-body failures.
DISPATCH_FAILED: regional service dispatch fails502502, JSON error string. The target may already have received the request.
RECURSIVE_REQUEST: internal hop marker received400400, JSON error string.
NOT_CONFIGURED: service key missing503503, JSON error string.

For a region hint, an unavailable trace does not block the target request. Inspect the missing colo or location.error. For strict colo/node selections, failed verification blocks the target request.

LimitProxyProbe
Request size1 MiB body1 MiB JSON envelope
Target timeout15 seconds until response headers100 to 30,000 ms including captured body; default 15,000 ms
Response sizeStreamed without a RegionHop capture cap1 MiB captured by default; configurable up to 5 MiB
Redirects / retriesNeither followed nor retried by RegionHopNeither followed nor retried by RegionHop

After proxy headers are sent, a body failure terminates the stream; the status cannot be changed. Runtime/platform limits still apply. Redirect Location is passed through unchanged. If your client follows an absolute redirect, it may leave RegionHop.

Cookies, URL origins, and CORS headers are not rewritten. Browser CORS and CSP rules still apply. This is an HTTP API relay; CONNECT, WebSocket, and whole-browser tunneling are not supported. Target payloads and responses are not persisted by RegionHop.

Track your allowance.

Open the playground to enter a target URL, method, headers and body, choose a location, and inspect a captured response. It uses your signed-in session and the same account allowance as your keys. Redirects are not followed. Responses are displayed as text, with a 1 MiB capture limit and a 15 second timeout.

Your account shows current minute and UTC day usage. GET /usage with Authorization: Bearer YOUR_KEY returns asOf and minute/day objects with used, remaining, limit, and ISO resetAt. Reading usage does not consume quota.

Response headerMeaning
X-RegionHop-Limit-Minute / X-RegionHop-Limit-DayAccount limits: 120 per minute and 10,000 per UTC day.
X-RegionHop-Remaining-Minute / X-RegionHop-Remaining-DayRequests remaining after this request. Shared across keys and the playground.
X-RegionHop-Reset-Minute / X-RegionHop-Reset-DayNext fixed-window boundary as Unix seconds.

These headers accompany admitted personal-key API requests, including errors, and quota rejections. RegionHop quota rejections return 429 with Retry-After in seconds and consume neither allowance. Authenticated catalog reads, validation failures, and target failures count. Account management and usage reads are free. Administrator credentials are unmetered and do not receive account quota headers. Target rate-limit headers remain separate.

See your request stats.

Your account page shows request volume, target response classes, RegionHop failures, request modes, and average target-header latency by observed colo. Choose 24 hours or 7 days. New history starts when tracking is enabled; earlier requests cannot be reconstructed.

GET /stats?hours=24 or GET /stats?hours=168 uses your personal bearer key and does not consume quota. The default is 24. It returns asOf, from, trackingSince, a summary, hourly timeline, colos, and modes. Totals contain requests, target2xx, target3xx, target4xx, target5xx, regionhopErrors, timedRequests, and averageHeadersMs. Missing timings are null, not zero.

Stats count admitted proxy requests and POST probe/playground attempts, including validation failures. Target 4xx/5xx responses are separate from RegionHop failures. Quota rejections, catalog reads, account management, unauthenticated requests and administrator credentials are excluded, so this total can differ from quota usage. Proxy stats describe the response through receipt of target headers; later streaming interruptions are not recorded.

Latency is measured from the regional node to target response headers. It excludes authentication, location verification, and body download. Averages mix the targets you called and are not a network speed ranking. The colo is a trace observation, not a guarantee of target-specific egress. Counts use 24 or 168 UTC hour buckets, including the current partial hour. Writes are asynchronous and best effort; refresh to see recent requests.

RegionHop retains seven days of hourly aggregates in the existing database, with hourly cleanup and deletion when the account is deleted. No target URLs, headers, bodies or individual request history are stored. There is no separate analytics service.

06 / DISCOVERY

Read available locations.

EndpointAuthenticationResponse
GET /regionsBearer key{regions, placement}: all supported hint names and a placement note.
GET /nodesBearer key{nodes, colos, placement}: active node records and selectable observed colo codes. Reads the catalog without running new checks.
GET /status.jsonPublicAggregate health, timestamps, node counts, per-colo states, and up to 24 hours of sampled history. No node IDs or credentials.
GET /statusPublicHuman-readable network status.
GET /healthPublic{"ok":true}. Worker liveness only, not catalog health.
Read the authenticated catalog
curl 'https://regionhop.com/nodes' \
  -H "Authorization: Bearer $REGIONHOP_KEY"

Node records include id, hint, registeredAt, checkedAt, location, lastKnownColo, and status; discovery-created nodes also record creationIngressColo. Inventory states are unchecked, observed, stale, or unavailable.

Public health states are healthy (all assigned nodes pass), degraded (some pass), unavailable (none pass), unknown (no completed observation), and stale (last sweep over 90 minutes old). Read checkedAt alongside health; generatedAt is the time the status response was generated. History records checks, not continuous uptime.

07 / OPERATIONS

Maintain the catalog.

Normal API use needs none of these calls. These endpoints share the Bearer key and can perform checks or allocate nodes.

Refresh, discovery, compaction, and tickets
EndpointArguments and behavior
POST /nodes/refreshNo body required. Inspect existing nodes without allocating. Returns the catalog plus checked. Does not record a scheduled-health history entry.
POST /nodes/check-healthNo body required. Run and record a health sweep. Returns {checked, nodes, checkedAt} or {checked:false, reason} if a check is already running.
POST /nodes/discoverOptional JSON object. strategy: hinted (default) or local. Hinted: regions array of 1 to 11 supported hints, default all; countPerRegion integer 1 to 3, default 1. Local: count integer 1 to 3, default 1; omit regions/countPerRegion. Returns catalog plus checked count. Request max 16 KiB. Active inventory max 128; capacity returns HTTP 409 with a JSON error string.
POST /nodes/compactNo body required. Retire surplus nodes, keeping two per known colo and preserving original hint routes. Returns {retired, nodes, colos, missingRedundancy}. Retired IDs are no longer selectable.
POST /nodes/ticketsOptional JSON: uses integer 1 to 40 (default 1); ttlSeconds integer 30 to 900 (default 300). Returns HTTP 201 with {token, url, uses, expiresAt}. Max 32 outstanding tickets; request max 4 KiB.
GET /nodes/seed/{token}Ticket authentication only. Consumes one use to create and inspect one unhinted node. Returns HTTP 201 with {node}. Invalid/expired/exhausted/revoked tickets return 410; capacity returns 409.
DELETE /nodes/tickets/{token}Bearer key. Revoke a ticket, returning HTTP 204.

Discovery creates instances, not guaranteed new locations. Local discovery uses the receiving Worker for creation; placement still varies. Tickets grant only bounded creation and trace inspection, not arbitrary proxy access. Compact after discovery if you want to restore two active nodes per known colo.