Skip to content

Public API

Aspire & Thrive — public API

Read-only paginated access to young person records.

Auth

An administrator can make an API key with the read:cyps scope from /settings/api-keys. The key chooses its organisation; a caller cannot select another one with a header. Send three headers on each record-list request:

Authorization: Bearer <prefix>.<secret>
X-Aspire-Timestamp: <unix seconds>
X-Aspire-Signature: <hmac_sha256(${timestamp}.${method}.${path}.${sha256(body)}, secret)>

Sign the uppercase method, the exact pathname and query string (including the ?), and the SHA-256 hash of the body. For GET the body is empty. Use the secret after the key's first dot as the HMAC key, with a Unix-seconds timestamp within five minutes of the server's clock. The OpenAPI JSON can be read without a key.

Endpoints

MethodPathSummary
GET/api/v1/cypsList young people for the API key's organisation

The record list accepts limit (1–100, default 50), status and cursor. Pass the returned next_cursor into the next request until it is empty. This endpoint allows 60 requests per minute per API key; wait for Retry-After after a rate-limit response. Single-record lookup and webhook subscription through API keys are not currently available.

Signed request with Node.js

Save the example as list-records.mjs and run it with Node.js 18 or later. Set AT_API_KEY in your environment and optionally AT_API_ORIGIN to your application address. Keep the key out of source code and logs.

import { createHash, createHmac } from "node:crypto";

const key = process.env.AT_API_KEY;
const dot = key?.indexOf(".") ?? -1;
if (!key || dot < 1 || dot === key.length - 1) throw new Error("Set AT_API_KEY to the full prefix.secret key.");
const url = new URL("/api/v1/cyps?limit=10", process.env.AT_API_ORIGIN || "https://aspire-and-thrive-web-9wzj.vercel.app");
const timestamp = String(Math.floor(Date.now() / 1000));
const bodyHash = createHash("sha256").update("").digest("hex");
const message = [timestamp, "GET", url.pathname + url.search, bodyHash].join(".");
const signature = createHmac("sha256", key.slice(dot + 1)).update(message).digest("hex");
const response = await fetch(url, {
  method: "GET",
  headers: {
    Authorization: "Bearer " + key,
    "X-Aspire-Timestamp": timestamp,
    "X-Aspire-Signature": signature,
  },
});
console.log("Status:", response.status);
if (response.ok) {
  const result = await response.json();
  console.log("Returned records:", result.data.length);
  console.log("More pages:", result.next_cursor !== null);
} else {
  console.log("Request failed. Check the status against the API documentation.");
}

Outbound webhooks

Operators subscribe to events from /admin/webhooks. Each delivery POSTs the envelope below to the subscriber URL with three headers: X-AT-Signature: sha256=<hex>, X-AT-Event, and X-AT-Delivery. Verify the signature using the per-webhook signing secret.

Zapier / n8n

There is no published Zapier app yet. Both tools work today using their generic HTTP blocks: