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.