n8n

Every workflow execution can end with a heartbeat. One HTTP Request node on the success path, one on the error path.

The setup

Add an HTTP Request node at the end of your workflow:

  • Method: GET
  • URL: https://eu.ingest.agentping.io/v1/ping?key={{ $env.AGENTPING_PING_TOKEN }}&agent=support-triage&status=ok

Store the ping token as an n8n environment variable, not inline. The token is per-agent; one per workflow keeps blast radius small.

For richer payloads, use POST against /v1/heartbeats with a JSON body assembled from n8n expressions:

{
  "id": "{{ $execution.id }}",
  "agent": "support-triage",
  "status": "ok",
  "started_at": "{{ $execution.startedAt }}",
  "finished_at": "{{ $now }}",
  "cost_usd": {{ $node["Compute Cost"].json.cost_usd }},
  "metadata": {
    "execution_id": "{{ $execution.id }}",
    "tickets_processed": {{ $node["Triage Loop"].json.count }}
  }
}

$execution.id is a useful idempotency key; retries become no-ops rather than duplicates.

Capturing cost

If your workflow calls an LLM via n8n's OpenAI or Anthropic nodes, the response includes token counts. Add a Function or Code node:

const usage = $node["OpenAI"].json.usage;
const inputCost = (usage.prompt_tokens / 1_000_000) * 5.00;
const outputCost = (usage.completion_tokens / 1_000_000) * 15.00;
return [{ json: { cost_usd: inputCost + outputCost } }];

Pipe the result into the heartbeat. See Heartbeats for why heartbeat cost is trusted.

Status from exit state

Wire a second HTTP Request node to n8n's error connector with status=fail:

https://eu.ingest.agentping.io/v1/ping?key={{ $env.AGENTPING_PING_TOKEN }}&agent=support-triage&status=fail&metadata={{ $json.error.message | url_encode }}

Two nodes, same agent, opposite outcomes.

Schedule monitoring

If the workflow runs on a Schedule Trigger, set the same cron on the agent. Pulse pages you when a run misses its window. n8n tells you a run happened; Pulse tells you when one didn't.