Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: HookPulse Endpoints API
version: 2d690e87
description: 'Dead-man switch for webhooks/cron. Index: GET /api/.'
servers:
- url: https://hookpulse.net
tags:
- name: Endpoints
paths:
/api/endpoints:
get:
operationId: list_endpoints
summary: Lists the owner's monitors, with the state of each one
description: 'Returns: { endpoints[{id,name,interval_sec,alert_to,alert_url,last_event_at,last_status,last_latency_ms,miss_count,alerted_at,active,healthy,overdue,waiting_first_ping,created_at,ingest_url,token?,status_url?,events_url?,curl_example?,templates?}], guest, billing?{provider,mode,network,chain_id,pay_to,homolog,dev,dev_gate,facilitator,asset,asset_address,faucet,wallets,product,free_max_endpoints,free_min_interval_sec,free_email_alerts,prices,usage,trial} }'
security:
- bearerAuth: []
responses:
'200':
description: '{ endpoints[{id,name,interval_sec,alert_to,alert_url,last_event_at,last_status,last_latency_ms,miss_count,alerted_at,active,healthy,overdue,waiting_first_ping,created_at,ingest_url,token?,status_url?,events_url?,curl_example?,templates?}], guest, billing?{provider,mode,network,chain_id,pay_to,homolog,dev,dev_gate,facilitator,asset,asset_address,faucet,wallets,product,free_max_endpoints,free_min_interval_sec,free_email_alerts,prices,usage,trial} }'
content:
application/json:
schema:
type: object
properties:
endpoints:
type: array
items:
$ref: '#/components/schemas/Monitor'
description: The owner's monitors, without the secret fields.
guest:
type: string
description: The guest that owns this list.
nullable: true
billing:
allOf:
- $ref: '#/components/schemas/Billing'
description: Prices and allowance, to decide before creating the next one.
required:
- endpoints
- guest
'401':
description: No credential, or an invalid one. See this endpoint's auth.
tags:
- Endpoints
post:
operationId: create_endpoint
summary: 'Creates a dead-man switch: silence beyond the interval becomes an alert'
description: 'This response is the only one that shows the monitor''s `token` and the `templates` — keep them. The second monitor, or an interval below the free minimum, answers **402 with `accepts[]`**: pay and repeat. A miss alerts at most once per 24h (or per interval, if it is longer).
Returns: { id, name, interval_sec, alert_to, alert_url, last_event_at, last_status, last_latency_ms, miss_count, alerted_at, active, healthy, overdue, waiting_first_ping, created_at, ingest_url, token?, status_url?, events_url?, curl_example?, templates?{ingest_curl,ingest_cron,ingest_n8n,miss_json,miss_url_hint} }'
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: Name to recognise the monitor in the alert.
interval_sec:
type: integer
description: Tolerated silence, in seconds. Below the free minimum, it costs.
alert_to:
type: string
description: E-mail to alert on a miss; without it, the account is alerted.
alert_url:
type: string
description: Public HTTPS URL that receives a POST on a miss (Slack Incoming, Discord, n8n).
required:
- name
example:
name: prod cron
interval_sec: 900
alert_to: optional@email.com
alert_url: https://n8n.example/webhook/hp
responses:
'200':
description: '{ id, name, interval_sec, alert_to, alert_url, last_event_at, last_status, last_latency_ms, miss_count, alerted_at, active, healthy, overdue, waiting_first_ping, created_at, ingest_url, token?, status_url?, events_url?, curl_example?, templates?{ingest_curl,ingest_cron,ingest_n8n,miss_json,miss_url_hint} }'
content:
application/json:
schema:
$ref: '#/components/schemas/Monitor'
'400':
description: Empty name, invalid interval or an `alert_url` that is not public HTTPS.
'401':
description: No credential, or an invalid one. See this endpoint's auth.
'402':
description: 'Quota exceeded. The response carries `accepts[]` (x402, USDC on Base): pay and repeat the same call with `X-PAYMENT`.'
tags:
- Endpoints
/api/endpoints/{id}:
get:
operationId: get_endpoint
summary: State of one monitor — accepts the owner's token or the monitor's own token
description: 'The monitor token only reads: it lets you put the state on a third-party dashboard without handing over the owner''s credential.
Returns: { id, name, interval_sec, alert_to, alert_url, last_event_at, last_status, last_latency_ms, miss_count, alerted_at, active, healthy, overdue, waiting_first_ping, created_at, ingest_url, token?, status_url?, events_url?, curl_example?, templates?{ingest_curl,ingest_cron,ingest_n8n,miss_json,miss_url_hint} }'
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: token
in: query
required: false
schema:
type: string
description: Monitor token, alternative to the `X-Hook-Token` header.
responses:
'200':
description: '{ id, name, interval_sec, alert_to, alert_url, last_event_at, last_status, last_latency_ms, miss_count, alerted_at, active, healthy, overdue, waiting_first_ping, created_at, ingest_url, token?, status_url?, events_url?, curl_example?, templates?{ingest_curl,ingest_cron,ingest_n8n,miss_json,miss_url_hint} }'
content:
application/json:
schema:
$ref: '#/components/schemas/Monitor'
'401':
description: No credential, or an invalid one. See this endpoint's auth.
'404':
description: The resource does not exist (or is not yours — the API does not tell the two apart on purpose).
tags:
- Endpoints
patch:
operationId: patch_api_endpoints_by_id
summary: Changes the monitor's name, interval or alert channels
description: 'Lowering the interval below the free minimum costs: the response becomes 402 with `accepts[]` until paid.
Returns: { ok, endpoint{id,name,interval_sec,alert_to,alert_url,last_event_at,last_status,last_latency_ms,miss_count,alerted_at,active,healthy,overdue,waiting_first_ping,created_at,ingest_url,token?,status_url?,events_url?,curl_example?,templates?} }'
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description: New monitor name, as it shows in the alert.
interval_sec:
type: integer
description: New tolerated silence, in seconds.
alert_to:
type: string
description: New alert e-mail; `null` turns it off.
alert_url:
type: string
description: New alert URL; `null` turns it off.
example:
name: …
interval_sec: 300
alert_to: null
alert_url: null
responses:
'200':
description: '{ ok, endpoint{id,name,interval_sec,alert_to,alert_url,last_event_at,last_status,last_latency_ms,miss_count,alerted_at,active,healthy,overdue,waiting_first_ping,created_at,ingest_url,token?,status_url?,events_url?,curl_example?,templates?} }'
content:
application/json:
schema:
type: object
properties:
ok:
type: boolean
description: Always `true`.
endpoint:
allOf:
- $ref: '#/components/schemas/Monitor'
description: The monitor with the change applied.
required:
- ok
- endpoint
'400':
description: Invalid field in the body.
'401':
description: No credential, or an invalid one. See this endpoint's auth.
'402':
description: 'Quota exceeded. The response carries `accepts[]` (x402, USDC on Base): pay and repeat the same call with `X-PAYMENT`.'
'404':
description: The resource does not exist (or is not yours — the API does not tell the two apart on purpose).
tags:
- Endpoints
delete:
operationId: delete_endpoint
summary: Deactivates the owner's monitor; it stops taking pings and alerting
description: 'Returns: { ok }'
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: '{ ok }'
content:
application/json:
schema:
$ref: '#/components/schemas/Ok'
'401':
description: No credential, or an invalid one. See this endpoint's auth.
'404':
description: The resource does not exist (or is not yours — the API does not tell the two apart on purpose).
tags:
- Endpoints
/api/endpoints/{id}/events:
get:
operationId: list_events
summary: The latest pings received at this monitor's ingest
description: 'Returns: { events[{at,status,latency_ms,source}] }'
security:
- bearerAuth: []
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: token
in: query
required: false
schema:
type: string
description: Monitor token, alternative to the `X-Hook-Token` header.
responses:
'200':
description: '{ events[{at,status,latency_ms,source}] }'
content:
application/json:
schema:
type: object
properties:
events:
type: array
items:
$ref: '#/components/schemas/Ping'
description: The most recent pings, newest first.
required:
- events
'401':
description: No credential, or an invalid one. See this endpoint's auth.
'404':
description: The resource does not exist (or is not yours — the API does not tell the two apart on purpose).
tags:
- Endpoints
components:
schemas:
Ping:
type: object
properties:
at:
type: string
description: When it arrived (UTC).
status:
type: integer
description: Status reported by the caller, when it did.
nullable: true
latency_ms:
type: integer
description: Latency reported by the caller, in ms.
nullable: true
source:
type: string
description: 'Where it came from: `get` or `post`.'
nullable: true
required:
- at
- status
- latency_ms
- source
description: A ping received at the ingest — the proof of life.
Billing:
type: object
properties:
provider:
type: string
description: Always `x402` — the only billing protocol accepted.
mode:
type: string
description: 'Seller mode: `live` charges for real, `dev` lets calls through unpaid.'
network:
type: string
description: 'USDC network: `base` in production, `base-sepolia` in staging.'
chain_id:
type: integer
description: EVM chain ID of the network above, so the wallet signs on the right chain.
pay_to:
type: string
description: Address that receives the payment.
nullable: true
homolog:
type: boolean
description: 'Staging seam on: the loop can be closed without spending USDC.'
dev:
type: boolean
description: 'Development mode: the 402 is simulated.'
dev_gate:
type: string
description: How dev mode is unlocked, when it exists.
nullable: true
facilitator:
type: string
description: URL of the facilitator that verifies and settles the payment.
asset:
type: string
description: Accepted currency — always `USDC`.
asset_address:
type: string
description: USDC contract on the network above.
faucet:
type: string
description: Test-USDC faucet; only on base-sepolia.
nullable: true
wallets:
type: object
description: Links to wallets that speak x402 (metamask, coinbase, base_app).
product:
type: string
description: Name of the product charging.
free_max_endpoints:
type: integer
description: Free monitors per owner.
free_min_interval_sec:
type: integer
description: Shortest interval that is still free. Below it, it costs.
free_email_alerts:
type: integer
description: Free e-mail alert registrations; the rest is paid (it is SES cost per miss).
prices:
allOf:
- $ref: '#/components/schemas/Precos'
description: What each paid action costs, in USD.
usage:
type: object
description: How much of the allowance the owner has used.
trial:
allOf:
- $ref: '#/components/schemas/Trial'
description: The account's trial, when there is a session.
required:
- provider
- mode
- network
- chain_id
- pay_to
- homolog
- dev
- dev_gate
- facilitator
- asset
- asset_address
- faucet
- wallets
- product
- free_max_endpoints
- free_min_interval_sec
- free_email_alerts
- prices
- usage
- trial
description: 'Everything that decides whether the next call will cost: x402 configuration, allowance, prices and trial.'
Trial:
type: object
properties:
days:
type: integer
description: Trial length in days.
active:
type: boolean
description: Whether it is in force now.
days_left:
type: integer
description: How many days remain.
ends_at:
type: string
description: When it ends (UTC).
nullable: true
granted:
type: boolean
description: '`true` when THIS call granted the trial.'
required:
- days
- active
- ends_at
description: The period without the usage paywall that confirming the e-mail grants. It is the alternative to paying.
Precos:
type: object
properties:
extra_endpoint_usd:
type: number
description: Monitor beyond the allowance.
fast_interval_usd:
type: number
description: Interval below the free minimum.
email_alert_usd:
type: number
description: E-mail alert registration beyond the first.
contact_agent_usd:
type: number
description: Agent contact.
required:
- extra_endpoint_usd
- fast_interval_usd
- email_alert_usd
- contact_agent_usd
description: Prices in force, in dollars. Read them here, not from the documentation.
Monitor:
type: object
properties:
id:
type: string
description: Monitor ID; it is the `:id` of the ingest URL.
name:
type: string
description: Name you gave it, to recognise it in the alert.
interval_sec:
type: integer
description: Tolerated silence, in seconds. Past that, it is a miss.
alert_to:
type: string
description: E-mail alerted on a miss.
nullable: true
alert_url:
type: string
description: HTTPS URL that receives a POST on a miss (Slack, Discord, n8n).
nullable: true
last_event_at:
type: string
description: Last ping received (UTC); `null` while it never pinged.
nullable: true
last_status:
type: integer
description: HTTP status the last ping sent, when it did.
nullable: true
last_latency_ms:
type: integer
description: Latency reported in the last ping, in ms.
nullable: true
miss_count:
type: integer
description: How many times this monitor has gone silent.
alerted_at:
type: string
description: When the last alert went out — it is what holds the 1 alert/24h cap.
nullable: true
active:
type: boolean
description: Whether the monitor is on.
healthy:
type: boolean
description: '`true` when it has pinged at least once and is not overdue.'
overdue:
type: boolean
description: '`true` when the silence passed `interval_sec`.'
waiting_first_ping:
type: boolean
description: '`true` while it never pinged. Neither healthy nor overdue: nobody has wired it yet.'
created_at:
type: string
description: When the monitor was created (UTC).
ingest_url:
type: string
description: The URL your cron/webhook calls to prove life.
token:
type: string
description: Read token of this monitor. Only comes on creation and to the owner.
status_url:
type: string
description: Status of this monitor with the token already in the query.
events_url:
type: string
description: Latest pings with the token already in the query.
curl_example:
type: string
description: The ingest `curl`, ready to paste in the cron.
templates:
allOf:
- $ref: '#/components/schemas/Templates'
description: Ingest snippets and the alert body, with this monitor already in them.
required:
- id
- name
- interval_sec
- alert_to
- alert_url
- last_event_at
- last_status
- last_latency_ms
- miss_count
- alerted_at
- active
- healthy
- overdue
- waiting_first_ping
- created_at
- ingest_url
description: 'A dead-man switch: the thing you make ping. If the ping stops for longer than `interval_sec`, it becomes `overdue` and the alert goes out.'
Templates:
type: object
properties:
ingest_curl:
type: string
description: A `curl` that works as proof of life.
ingest_cron:
type: string
description: The equivalent crontab line.
ingest_n8n:
type: string
description: How to call the ingest from n8n.
miss_json:
type: string
description: The exact JSON we POST to `alert_url` when the silence becomes a miss.
miss_url_hint:
type: string
description: What works as `alert_url` — public HTTPS only.
required:
- ingest_curl
- ingest_cron
- ingest_n8n
- miss_json
- miss_url_hint
description: How to ping and what we send when it fails. It is what saves guessing the format.
Ok:
type: object
properties:
ok:
type: boolean
description: Always `true` — failure comes as a 4xx/5xx status, not as `ok:false`.
required:
- ok
description: Write confirmation with no body of its own to return.
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: 'Guest token (`POST /api/guest`) in `X-Guest-Token: hp_…` or `Authorization: Bearer hp_…`. A `sess_…` session also works.'