Stateful API Poller

readyNode-RED→ n8n target

8 nodes · OAuth token refresh · dual HTTP paths · global state — a realistic inherited flow, not a toy example. Use the tabs above to view edge cases or the n8n migration output.

Flow diagram

Click any node to inspect scripts, API calls, and auth logic — same canvas as the signed-in product.

Poll Interval (10s)

inject

What it does

Triggers flow execution on a schedule, event, or manual inject

No external scripts, queries, or commands in this node.

Critical integrations

API calls, database queries, scripts, and commands that this flow depends on.

API / HTTPhttps://api.external-service.com/oauth/token

Outbound HTTP POST request

Nodes: POST Auth Handshake

POST https://api.external-service.com/oauth/token
API / HTTPhttps://api.external-service.com/v1/metrics

Outbound HTTP GET request

Nodes: Fetch Remote Metrics

GET https://api.external-service.com/v1/metrics
ScriptCommit Token to State

Custom JavaScript executed in flow

Nodes: Commit Token to State

if (msg.statusCode === 200 && msg.payload.access_token) {
    global.set("auth_bearer_token", msg.payload.access_token);
    // Expire 5 minutes early for safety buffer
    let expiryTime = Date.now() + ((msg.payload.expires_in - 300) * 1000);
    global.set("token_expiry", expiryTime);
    node.status({fill:"green",shape:"dot",text:"Token Updated"});
} else {
    node.error("Authentication flow failed completely.", msg);
}
return null;
ScriptRead Global Auth Token

Custom JavaScript executed in flow

Nodes: Read Global Auth Token

// Read state from global context store
let token = global.get("auth_bearer_token");
let expires = global.get("token_expiry") || 0;

if (!token || Date.now() > expires) {
    node.status({fill:"red",shape:"dot",text:"Token Expired"});
    // Route to Output 2: Re-authenticate
    return [null, { payload: "auth_handshake_required" }];
}

msg.headers = {
    "Authorization": "Bearer " + token,
    "Accept": "application/json"
};
// Route to Output 1: Token Valid, proceed to fetch
return [msg, null];

Documentation

Summary

Polls a remote metrics API every 10 seconds with OAuth bearer-token auth stored in global context. Expired tokens trigger a re-authentication handshake before retrying. Responses pass through rate-limit header inspection and a join gate before batch logging.

External systems

  • External metrics API (api.external-service.com)
  • OAuth token endpoint
  • Node-RED global context (auth_bearer_token, token_expiry, rate_limit_remaining)

Detailed documentation

Overview

Stateful API Poller

Trigger & schedule

An inject node fires every 10 seconds, starting the poll cycle.

Auth gate (dual-output function)

A function node reads auth_bearer_token and token_expiry from global context:

  • Output 1 (valid token): attaches Authorization: Bearer … headers and proceeds to metrics fetch.
  • Output 2 (expired/missing): routes to the OAuth token handshake.

Metrics path

  • GET https://api.external-service.com/v1/metrics with bearer auth.
  • Parallel branches: inspect x-ratelimit-remaining response header into global state, and feed a join node that waits for batch completion (5s timeout).
  • Final debug output logs the aggregated metric array.

Re-auth path

  • POST https://api.external-service.com/oauth/token when the token is stale.
  • Function node commits access_token and expiry (minus 5-minute safety buffer) back to global context.

Operational notes

Global context.store state does not migrate literally to n8n — FlowShift maps this to workflow static data or credential-backed token refresh nodes in the target export.

Try it with your own file

Sign up free to upload your workflow export or code file and get the same diagram, documentation, edge cases, and migration output.

Upload your own flow →