Docs

Type a word or a question. Esc closes the search.

Sign in Start free
Developers/Start

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_ID

The 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 a webhook.test event. Its body is JSON with id, type, created_at and data; the X-Up4-Signature header signs it. response_body reads "HTTP 200".
  • "response_code": null: up4 got no answer. response_body says "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 a 400 before anything is sent.
  • Any other code: your server answered with an error, and response_body is 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