Skip to navigation

Metric webhooks

A key result in OKR Hub can score itself from the number it measures. Whoever may update the key result connects a metric on its page: a name, a baseline (which scores 0.0), a target (1.0) and, for a webhook, an address with a secret. Each number posted there becomes a grade between the baseline and the target, linear and kept between 0 and 1, recorded as a check-in by whoever set the metric up and marked as the metric’s.

The webhook sits outside the versioned API: no API key, no scopes, just the metric’s own secret. Metrics are set up, paused and given new secrets on the key result’s page, not through the API, which reads them: a key result’s metric says which one drives it, and a check-in’s metric which one recorded it.

Posting a number

curl -X POST "$METRIC_WEBHOOK_URL" \
-H "Authorization: Bearer $METRIC_SECRET" \
-H "Content-Type: application/json" \
-d '{ "value": 42 }'

The address (…/api/okrhub/metrics/<sourceId>, on Taktoria’s own domain) and the secret (it starts tkm_) are on the key result’s page. The secret is shown once, when the metric is connected or given a New secret; keep it like a password, since it lets anyone who holds it move the key result’s score.

FieldTypeMeaning
valuenumber or stringThe number. A string may carry thousands separators or a trailing % ("1,234", "87.5%"). Required.
atISO 8601 dateWhen the number stood there, if not now. A late one goes into the history at its date; more than five minutes ahead is refused.
notestringShown on the check-in, up to 500 characters.
testtrueCheck the secret and the value and answer the grade it would make, recording nothing.

A good answer is 200:

{ "ok": true, "recorded": true, "value": 42, "score": 0.42 }

recorded is false when the grade is the one the metric last made: the number is remembered but adds nothing to the history, so posting a flat metric every day is fine. A test answers "test": true and "recorded": false.

How it sits beside people’s check-ins

A person may still check in on a key result a metric drives. Their check-in stands in the history beside the metric’s, and is the key result’s latest until the metric next moves. A Final grade on the scorecard is the score whatever the metric does.

The metric writes as whoever set it up, and only while they could have written it themselves: still in the workspace, holding an OKR Hub seat, not a Viewer, and allowed to update the key result. When they no longer are, the webhook answers 403 until somebody who may update the key result saves its settings and so takes it over.

Answers

Errors are a JSON body with one code, { "error": "paused" }, rather than the versioned API’s error object.

StatusCodeMeaning
200Recorded, or remembered with nothing to record (recorded: false), or a test
400invalid_jsonThe body is not JSON
400value_invalidNo number in value, or a body that is not an object
400at_invalidat is not a date, or is more than five minutes ahead
401unauthorizedNo secret, a wrong one, or no such webhook: the three answer alike, so the address says nothing about whether it exists
403configurer_cannot_updateWhoever set the metric up may no longer update the key result
409pausedThe metric is paused; resume it on the key result’s page. A test still answers
413too_largeThe body is over 16 KB
429rate_limitedA limit is used up: wait Retry-After seconds

Limits

metric-webhook-ip allows 600 requests per 10 minutes from one address, counted before the secret is checked, and metric-webhook 60 an hour per metric once it is. A metric moves daily, not by the second: post when the number changes. Answers past the secret carry the rate limit headers described under Errors and pagination.