/monitors (POST)
const url = 'https://culipulse.dev/v1/monitors';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"name":"API health","type":"http","target":"https://api.example.com/health","interval_seconds":60,"timeout_ms":1,"method":"example","expected_status":"2xx","body_match":"example","follow_redirects":true,"down_after_failures":1,"up_after_successes":1,"down_min_sources":1,"sla_target":1,"grace_seconds":1,"agent_sources":["example"],"check_spec":{"request":{"headers":{"additionalProperty":"example"},"secretHeaders":{"additionalProperty":"example"},"preserveSecretHeaders":true,"secretHeaderNames":["example"],"auth":{"type":"bearer","token":"example","username":"example","password":"example"},"body":"example","bodySecret":true,"preserveBody":true,"contentType":"example"},"assertions":[{"source":"text_body","op":"example","value":"example","path":"example","name":"example"}],"transport":{"payload":"example","payloadEncoding":"utf8","expect":"example","expectMode":"contains","payloadSecret":true,"preservePayload":true},"domain":{"warnDays":1},"ping":{"count":1,"lossDegradedPct":1,"rttDegradedMs":1},"heartbeat":{"token":"example","failEnabled":true,"maxDurationSeconds":1},"dns":{"records":[{"type":"example","mode":"example","expected":["example"]}],"crossCheck":true},"vendor":{"vendorId":"example","pageUrl":"example","probeUrl":"example","components":["example"]},"dependencies":["example"]},"warn_days":1,"components":["example"],"dependencies":["example"]}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://culipulse.dev/v1/monitors \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "name": "API health", "type": "http", "target": "https://api.example.com/health", "interval_seconds": 60, "timeout_ms": 1, "method": "example", "expected_status": "2xx", "body_match": "example", "follow_redirects": true, "down_after_failures": 1, "up_after_successes": 1, "down_min_sources": 1, "sla_target": 1, "grace_seconds": 1, "agent_sources": [ "example" ], "check_spec": { "request": { "headers": { "additionalProperty": "example" }, "secretHeaders": { "additionalProperty": "example" }, "preserveSecretHeaders": true, "secretHeaderNames": [ "example" ], "auth": { "type": "bearer", "token": "example", "username": "example", "password": "example" }, "body": "example", "bodySecret": true, "preserveBody": true, "contentType": "example" }, "assertions": [ { "source": "text_body", "op": "example", "value": "example", "path": "example", "name": "example" } ], "transport": { "payload": "example", "payloadEncoding": "utf8", "expect": "example", "expectMode": "contains", "payloadSecret": true, "preservePayload": true }, "domain": { "warnDays": 1 }, "ping": { "count": 1, "lossDegradedPct": 1, "rttDegradedMs": 1 }, "heartbeat": { "token": "example", "failEnabled": true, "maxDurationSeconds": 1 }, "dns": { "records": [ { "type": "example", "mode": "example", "expected": [ "example" ] } ], "crossCheck": true }, "vendor": { "vendorId": "example", "pageUrl": "example", "probeUrl": "example", "components": [ "example" ] }, "dependencies": [ "example" ] }, "warn_days": 1, "components": [ "example" ], "dependencies": [ "example" ] }'Authorizations
Section titled “Authorizations”Request Body
Section titled “Request Body”object
Example
API healthOne of http, tcp, icmp, udp, domain, heartbeat, dns, vendor. Defaults to http. Cannot be changed later.
Example
httpUp to 2,048 characters. Not used by heartbeat monitors. http: a literal private, loopback or link-local IP (like 192.168.1.10) is accepted only when every location is one of your own agents; with any shared location, or none, it is a 400. tcp and udp: host:port only, port 1 to 65535: no https://, no path, no spaces, and an IPv6 address in square brackets, like [2001:db8::1]:53. icmp (ping): a host name or an IPv4 address, like db.example.com or 192.0.2.10, with no port (ping has none), no https://, no path, no login and no spaces. IPv6 addresses are not supported for ping yet. Anything else is a 400. A target saved before this rule was added keeps working while you leave it unchanged.
Example
https://api.example.com/healthWhole seconds, at most 31,536,000 (365 days), and not below your plan’s fastest check. Anything above the maximum is a 400.
Example
60Max 10000 and less than interval_seconds × 1000.
Case-insensitive. One of GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS; anything else is a 400.
Codes like ‘200’, ‘2xx’ or ‘200,301’, up to 128 characters.
Example
2xxText the response body must contain (case-sensitive, up to 1,024 characters). Only http monitors; the first 1 MiB of the body is searched. Send an empty string or null to clear.
Integer 1..5. Consecutive failed checks before the monitor is marked down. Ignored for heartbeat monitors (still accepted and stored): a heartbeat goes down at the first missed deadline, so use grace_seconds to allow lateness.
Integer 1..5. Consecutive successful checks before a down monitor is marked up again. Ignored for heartbeat monitors (still accepted and stored): a heartbeat is up again at its first ping.
Integer 1..number of agents. Only applies to monitors that check from agents; for vendor, domain and dns only 1 is accepted.
Percent in (0, 100]. null clears it.
Heartbeat only. A whole number of seconds from 1 to 2,592,000 (30 days); anything else is a 400. Extra seconds allowed after the expected ping before it counts as missed. This, not down_after_failures, is how you tolerate a late ping. Defaults to 20% of the interval, at least 60, at most 2,592,000.
Agent ids to probe from. Omit on PATCH to keep the current set.
object
HTTP monitors: what to send.
object
Plain request headers. Up to 50 headers in total (plain + secret), names up to 256 characters, values up to 8192 characters. The whole check_spec may be at most 128 KB.
object
Write-only. Headers stored encrypted; reads return their names in secretHeaderNames. Send {} to clear. Same limits as headers.
object
Write-only. true keeps the stored secret headers.
Read-only. Names of the stored secret headers.
Reads return type only. Send type alone to keep the stored credentials.
object
Request body, up to 65,536 characters.
On write, stores body encrypted. On read, true means a secret body is set (it isn’t returned).
Write-only, with bodySecret: true keeps the stored secret body.
HTTP monitors: extra checks on the response.
object
Json_body only.
Header only.
TCP and UDP monitors: what to send and expect (the expected reply is the banner check).
object
What to send, up to 1,024 bytes. With payloadEncoding utf8 (the default) these escapes are turned into real characters when the check runs: \r, \n, \t, \xHH (00 to 7F) and \\ for one backslash, so PING\r\n sends PING and a line break. Any other backslash is sent as typed. With hex it is a hex string (0d0a is a line break) and nothing is interpreted.
On write, stores payload encrypted. On read, true means a secret payload is set.
Write-only, with payloadSecret: true keeps the stored secret payload.
Days of warning before a domain or certificate expires.
object
ICMP monitors.
object
Heartbeat monitors. The server creates the token and keeps it on update.
object
The secret in the monitor’s ping URL: https://culipulse.dev/ping/<token> (add /start, /fail, or an exit code such as /0 to the end). Anyone who has it can check the monitor in or mark it down, so it is returned only to tokens with the write scope; with a read-only token it is left out.
Always true. /fail, or a check-in with a non-zero exit code (such as /2), always marks the monitor down; that can’t be turned off. A bare ping or /start doesn’t. Sending false is a 400.
Run-time limit in seconds, measured from the job’s /start ping to its finishing ping. It only applies to runs that send /start. A run with no finishing ping by the limit is flagged (degraded) at that moment. 0 or omitted means no limit.
DNS monitors.
object
object
Read-only. Vendor status monitors: set by the server from target.
object
Read-only. Ids of the vendor monitors this monitor depends on.
Http: days of warning before the site’s domain expires; 1 or more turns the check on, 0 turns it off. domain: the warning threshold, 1..3650 (default 30). Omit on PATCH to keep the current value.
Vendor monitors only: the status-page components to watch. Statuspage vendors: omit or send [] to watch the whole vendor. AWS: service:region targets, at least one. Omit on PATCH to keep the current list.
Ids of your vendor monitors this monitor depends on (up to 50); ids that aren’t one of your vendor monitors are ignored. Not allowed on vendor monitors. Omit on PATCH to keep the current list; send [] to clear it.
Responses
Section titled “Responses”Created
object
Present only when the save worked but something will not behave as you might expect, and repeated on every save while it stays true. own_agent_no_secrets: an agent you run is one of the monitor’s locations and the monitor has sign-in details, secret headers, a secret body or a secret payload. Agents you run never receive those, so their checks run without them. Unknown codes may be added later: show message and ignore codes you don’t know.
object
Plain-language text you can show to a person.
Example
{ "warnings": [ { "code": "own_agent_no_secrets" } ]}Invalid request
object
Present on some 400s so a client can branch without parsing error. Known values: channel_limit_reached, too_many_monitors, duplicate_webhook_url.
The request field the error is about, when there is one.
The limit that was hit, when code names one.
Example
{ "error": "not found", "request_id": "req_abc123", "code": "channel_limit_reached"}