Skip to main content

Emitting events

Every event goes through POST /v1/events, authenticated as one of two principal types. Which one you use changes what the server derives for you and what provenance the event gets — see Trust & render-tokens.

App vs. subject principal

The caller authenticates with their own SSO-JWT. actor is unconditionally the authenticated subject — nothing in the request body can override it.

import { CNSClient } from "@amphoze/cns-client";

const client = new CNSClient({
baseUrl: "https://cns.example.com",
getToken: () => getEndUserToken(),
});

const event = await client.emit("order.shipped", {
target: { subject_ids: ["sub_carrier_ops"] },
data: { order_id: "ord_123" },
});

provenance defaults to client-asserted. It escalates to backend-verified only if the request carries a verified render-token in metadata.render_token.

Equivalent curl

curl -s -X POST "$CNS_API/v1/events" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"event_type": "order.shipped",
"target": { "subject_ids": ["sub_carrier_ops"] },
"data": { "order_id": "ord_123" }
}'

202 Accepted with the fully server-stamped envelope on success. See API Reference → POST /v1/events for every field, status code, and the exact client-suppliable subset.

Ordering fields are yours to manage

session_id and seq are client-suppliable, and the ordering guarantees in Events & the envelope only hold if you manage them consistently: pick one session_id per SDK-instance lifetime (CNSClient defaults to a fresh UUID per instance) and increment seq for every event that instance emits, starting from 0. CNSClient.emit() does this bookkeeping for you automatically; CNSServer.emit() (app/publisher principal) does not manage a session/seq for you — pass your own if ordering matters for that event stream, or omit both and accept ingest_time-only ordering.