First request in a minute, a webhook in five.
Afterwards you have made an authenticated request, created a monitor and received a signed webhook on your own server. You need a terminal with curl and jq, and for the webhook a URL that can be reached from the internet.
1 · Create a key
In the app open Settings → API tokens and create a key with the scopes
self.read, monitor.read,
monitor.write, monitor.delete
and webhook.write. The key is shown once; put it in an
environment variable, not in a script.
export UP4_API_KEY="pls_…"2 · Ask who you are
The first request needs only self.read and shows what the key may do:
curl -s https://app.upfour.io/v1/me \
-H "Authorization: Bearer $UP4_API_KEY"{
"data": {
"auth_method": "api_key",
"org_role": "owner",
"scopes": ["self.read", "monitor.read", "monitor.write", "monitor.delete", "webhook.write"],
"api_version": "2026-05-07",
…
}
}
Every successful answer sits in data. A
401 means the header or the key is wrong:
keys and scopes lists the causes.
3 · Create a monitor
The Idempotency-Key makes a retry safe: the same key never
creates a second monitor. Put the key into a variable first, so that running the command again
sends the same key. The id goes into a variable for the next steps.
MONITOR_KEY=$(uuidgen)
MONITOR_ID=$(curl -s -X POST https://app.upfour.io/v1/monitors \
-H "Authorization: Bearer $UP4_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $MONITOR_KEY" \
-d '{
"name": "Example",
"url": "https://example.com",
"monitor_type": "http",
"interval_seconds": 60,
"regions": ["eu"]
}' | jq -r .data.id)
echo $MONITOR_IDThe monitor runs from now on and appears in the app's monitor list. Every field it accepts: monitors reference.
4 · Receive a webhook
Subscribe a URL of yours to the events you care about. It must be reachable from the internet and answer with a 2xx status: an endpoint of your application, or a tunnel to your machine while you try this out. Addresses in private networks are refused.
SUBSCRIPTION_KEY=$(uuidgen)
curl -s -X POST https://app.upfour.io/v1/webhook-subscriptions \
-H "Authorization: Bearer $UP4_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $SUBSCRIPTION_KEY" \
-d '{
"url": "https://your-server.example/up4-hook",
"events": ["monitor.status_changed", "incident.opened", "incident.resolved"]
}' > subscription.json
SUBSCRIPTION_ID=$(jq -r .data.id subscription.json)
jq -r .data.secret subscription.json # whsec_…, shown only in this response
Store the secret with your other secrets; your server needs it
to check the signature. If you run the create command again with the same key, the answer is the stored
one, secret included, and no second subscription appears. Then have up4 send a test event right away.
The call waits for that one delivery attempt (at most 10 seconds), which is why the
202 already carries the outcome:
curl -s -X POST https://app.upfour.io/v1/webhook-subscriptions/$SUBSCRIPTION_ID/test \
-H "Authorization: Bearer $UP4_API_KEY" | jq '.data | {event, response_code, response_body}'"response_code": 200: your server received awebhook.testevent. Its body is JSON withid,type,created_atanddata; theX-Up4-Signatureheader signs it.response_bodyreads"HTTP 200"."response_code": null: up4 got no answer.response_bodysays"Delivery timed out"when the server did not answer in time and"Delivery failed"for other errors such as a refused connection. Check that the URL is public and answers quickly. A host that does not resolve, or that resolves to a private address, is refused with a400before anything is sent.- Any other code: your server answered with an error, and
response_bodyis only the status line, for example"HTTP 502". up4 never keeps the text of your answer.
From now on a monitor that goes down or comes back sends monitor.status_changed
to this URL. How to check the signature and handle retries: webhook receiver recipe.
5 · Clean up
Delete the test monitor and the subscription when you are done. Both answer with 204.
curl -s -X DELETE https://app.upfour.io/v1/monitors/$MONITOR_ID \
-H "Authorization: Bearer $UP4_API_KEY"
curl -s -X DELETE https://app.upfour.io/v1/webhook-subscriptions/$SUBSCRIPTION_ID \
-H "Authorization: Bearer $UP4_API_KEY"Where next
- The contract: envelopes, errors, versions and limits in one page.
- Pagination: lists return pages; follow
pagination.next_cursor. - For AI assistants: which files to give a coding assistant.
- Monitors as code: keep your monitors in a file in your repository.
Was this page helpful?