Back to milestra.app

Developers

API & webhooks

Use the Milestra API to pull goals into dashboards (Power BI, Looker Studio, Excel), push numbers in from other systems, or trigger automations in Zapier and Make. Workspace admins create keys in Settings → API & webhooks.

Authentication

Send your key in the Authorization header. Keys are shown once when created; we only store a hash.

curl https://milestra.app/api/v1/goals \ -H "Authorization: Bearer mst_live_…"
  • Scopes: every key can read; tick “allow updating key results” to add the write scope.
  • Rate limit: 120 requests per minute per key. Over the limit you get HTTP 429 with a Retry-After header.
  • Pagination: limit (1–200, default 50) and offset; responses include pagination.total.
  • Errors: JSON {"error":{"code":"…","message":"…"}} with a matching HTTP status.

Endpoints

MethodPathWhat it does
GET/api/v1/meCheck your key and see the workspace it belongs to.
GET/api/v1/goalsList goals with progress and health. Filters: status, health (GREEN, AMBER, RED, GRAY), updated_since, limit, offset.
GET/api/v1/goals/{id}One goal with its key results, actions and owner ids.
GET/api/v1/key-resultsList key results. Filter: goal_id.
GET/api/v1/key-results/{id}One key result.
PATCH/api/v1/key-results/{id}Update current_value (needs a key with the write scope). Goal progress and health recalculate automatically.
GET/api/v1/actionsList action steps. Filters: status (open, completed, overdue), goal_id.

Example: update a key result

curl -X PATCH https://milestra.app/api/v1/key-results/KR_ID \ -H "Authorization: Bearer mst_live_…" \ -H "Content-Type: application/json" \ -d '{"current_value": 48}'

Webhooks

Add a webhook URL (https only) and choose events. Milestra sends a JSON POST within seconds of the change. Each delivery is logged; a webhook is paused automatically after 20 failed deliveries in a row.

EventWhen
goal.createdA goal is created in the app.
key_result.updatedA key result's current value changes (app or API).
check_in.submittedSomeone submits or updates their weekly check-in.
action.completedAn action step is marked done.
{ "id": "5f0c…", // unique delivery id (also in X-Milestra-Delivery) "event": "key_result.updated", "created_at": "2026-10-05T09:12:44.120Z", "organization_id": "…", "data": { "key_result": { "id": "…", "title": "Learners at grade level", "current_value": 48, "target_value": 60 } } }

Verifying signatures

Every request carries X-Milestra-Signature: t=<unix seconds>,v1=<hex>, where v1 is the HMAC-SHA256 of <t>.<raw body> using your webhook's signing secret. Reject requests whose signature doesn't match or whose timestamp is more than 5 minutes old.

import crypto from "node:crypto"; export function verify(secret, rawBody, header) { const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("="))); if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex"); return crypto.timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(v1, "hex")); }

Zapier and Make

  • Trigger: use “Webhooks by Zapier → Catch Hook” (or Make's Custom webhook) and paste its URL as a Milestra webhook.
  • Action: use “Webhooks by Zapier → Custom Request” with your API key to update a key result.