Skip to main content

Spin up your first state machine

Every action on the Zeq framework — wizard, prove, mail, message, playground, AI chat, app dev, contract transition — comes out of an API key bound 1:1 to a state machine. To get going you do five things:

  1. Register a Zeq identity (the ZEQ07XXXXXXXXX ZID).
  2. Spin up a state machine on that identity.
  3. Copy the zsm_… API key the spin-up returns to you (shown once).
  4. Send your first event into the entangled state.
  5. Read the entangled state back, then validate the entangled state integrity.

Every step below is a real, runnable call against the live API at https://zeqapi.com. If you're self-hosting, replace https://zeqapi.com with your local origin (https://localhost:3099 for the dev stack).


1. Register a Zeq identity

Identity in Zeq is equation-as-credential. The client computes an HMAC over your equation (the salt is generated client-side, version v2:), POSTs only the hash, and the server never sees the raw equation. The browser flow at /auth/ runs the wizard for you; the wire-level protocol is POST /api/zeq-auth/register-v3.

For a programmatic walk-through, the simplest path is to call /zeq/wizard/compute to get a candidate equation, then HMAC it client-side and POST the hash:

curl — generate a candidate equation
curl -sS https://zeqapi.com/api/zeq/wizard/compute \
-H "Content-Type: application/json" \
-d '{"query":"orbit of a satellite around earth"}'

Response (truncated):

{
"ok": true,
"equation": "□φ − μ²(r)φ − λφ³ … = T^μ_μ + …",
"operators": ["KO42", "NM21", "GR37"],
"envelope_id": 821334910,
"phase": 0.4119,
"zeqond": "2287439210.7",
"domain": "orbital-mechanics",
"pulseHz": 1.287,
"precision": 0.00071
}

Pick that equation up, HMAC it with the HITE key + your random 32-byte salt, then register:

curl — register
curl -sS https://zeqapi.com/api/zeq-auth/register-v3 \
-H "Content-Type: application/json" \
-d '{
"equation_hash": "0123abc...64hex...",
"equation_salt": "fedc...64hex...",
"display_name": "Pad",
"hash_version": 2
}'

You get back your ZID, a JWT token, your zid_email (zeq07xxxxxxxxx@zeq.dev), and — because of the auto-state-machine policy in zeqAuthV3.ts — your default state machine's slug and its first API key:

{
"ok": true,
"zid": "ZEQ07491829374",
"zid_email": "zeq07491829374@zeq.dev",
"token": "eyJ...",
"displayName": "Pad",
"plan": "free",
"hash_version": 2,
"state_machine": {
"slug": "zeq07491829374",
"api_key": "zsm_LIVE_KEY_SHOWN_ONCE_ONLY"
}
}

Save the api_key. The framework only stores its SHA-256 hash. If you lose this string you have to mint a new key from the portal.

If you'd rather take the browser path: open https://zeqapi.com/auth/, run the wizard, and your default state machine + key appear in /portal/.


2. Spin up an additional state machine (optional)

The register-v3 flow auto-creates one. You can spin up more — one per project, one per device, one per audit boundary. Use POST /api/chain/state-machines:

curl — spin up
curl -sS https://zeqapi.com/api/chain/state-machines \
-H "Authorization: Bearer ${ZSM_KEY}" \
-H "Content-Type: application/json" \
-d '{
"slug": "my-iot-fleet",
"is_public": false,
"display_name": "Production IoT fleet",
"purpose": "Audited heartbeats from the kitchen sensors"
}'
JavaScript (fetch)
const res = await fetch("https://zeqapi.com/api/chain/state-machines", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.ZSM_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
slug: "my-iot-fleet",
is_public: false,
display_name: "Production IoT fleet",
purpose: "Audited heartbeats from the kitchen sensors",
}),
});
const data = await res.json();
console.log(data.machine.slug, data.api_key);
Python (requests)
import os, requests

r = requests.post(
"https://zeqapi.com/api/chain/state-machines",
headers={"Authorization": f"Bearer {os.environ['ZSM_KEY']}"},
json={
"slug": "my-iot-fleet",
"is_public": False,
"display_name": "Production IoT fleet",
"purpose": "Audited heartbeats from the kitchen sensors",
},
)
print(r.json()["machine"]["slug"], r.json().get("api_key"))

Response (201 Created):

{
"ok": true,
"machine": {
"id": "uuid",
"slug": "my-iot-fleet",
"parent_origin": "zeq-dev",
"is_public": false,
"status": "active",
"genesis_zeqond": "2287439210",
"display_name": "Production IoT fleet",
"purpose": "Audited heartbeats from the kitchen sensors",
"owner_zid": "ZEQ07491829374",
"created_at": "2026-04-28T01:49:00.000Z"
},
"api_key": "zsm_..."
}

Slug rules: [a-z0-9-]{1,64}. If your machine collides with one you already own, the framework auto-appends -2, -3, … up to -100. User-supplied slugs collide loudly with 409 so you can correct an intentional choice.


3. Send your first event

Four write endpoints exist on the entangled state, each scoped to your machine:

EndpointPurpose
POST /api/chain/:slug/eventCatch-all log. Pre-hash with body.hash or send body.payload and the server hashes it.
POST /api/chain/:slug/stateState-hash snapshot. Caller pre-hashes; server records hash + Zeqond.
POST /api/chain/:slug/fileFile-hash event. Hash + name + bytes + mime.
POST /api/chain/:slug/connectionConnection event. Direction (inbound/outbound), peer hash, protocol, state.

The framework records the hash, never the bytes (free tier). If you need the bytes back later, you keep them — the entangled state proves what was claimed at Zeqond N.

curl — first event
curl -sS https://zeqapi.com/api/chain/my-iot-fleet/event \
-H "Authorization: Bearer ${ZSM_KEY}" \
-H "Content-Type: application/json" \
-d '{
"type": "heartbeat",
"payload": {"temp_c": 21.4, "uptime_ms": 12345}
}'
JavaScript
await fetch(`https://zeqapi.com/api/chain/${slug}/event`, {
method: "POST",
headers: {
"Authorization": `Bearer ${zsmKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
type: "heartbeat",
payload: { temp_c: 21.4, uptime_ms: 12345 },
}),
});
Python
requests.post(
f"https://zeqapi.com/api/chain/{slug}/event",
headers={"Authorization": f"Bearer {zsm_key}"},
json={"type": "heartbeat", "payload": {"temp_c": 21.4, "uptime_ms": 12345}},
)

Response (201):

{
"ok": true,
"zeqondNumber": 2287439213,
"transitionId": "9b1c…uuid"
}

That transitionId is on the entangled state forever, hashed against the previous transition's state_hash. Your event just became immortal.


4. Observe the entangled state

Pull the latest state, a specific block, or a windowed range:

curl — latest state
curl -sS "https://zeqapi.com/api/chain/my-iot-fleet/state" \
-H "Authorization: Bearer ${ZSM_KEY}"
curl — explore range
curl -sS "https://zeqapi.com/api/chain/my-iot-fleet/explore?from=0&to=999999999&limit=100" \
-H "Authorization: Bearer ${ZSM_KEY}"

For a live feed (useful in dashboards):

JavaScript — SSE
const es = new EventSource(
`https://zeqapi.com/api/chain/${slug}/explore/sse?token=${jwt}`,
);
es.onmessage = (e) => {
const tx = JSON.parse(e.data);
console.log("tx", tx.zeqond, tx.type, tx.stateHash);
};

EventSource doesn't support custom headers, so the SSE endpoint also accepts ?token=<jwt> for cookie-less auth.

To watch from a browser without code, point the State Explorer at your machine:

https://zeqapi.com/state/?slug=my-iot-fleet

5. Validate the entangled state (PoHC)

Proof of Harmonic Convergence — the entangled state is hash-linked from the genesis seed forward. To prove integrity over a window:

curl — validate
curl -sS "https://zeqapi.com/api/chain/my-iot-fleet/pohc/validate" \
-H "Authorization: Bearer ${ZSM_KEY}"
{
"ok": true,
"valid": true,
"count": 17,
"broken_at": null,
"genesis_zeqond": "2287439210"
}

If a row's prev_hash doesn't match the previous row's state_hash, valid flips to false and broken_at carries the offending Zeqond number.

You can also bound the window: ?from=2287439210&to=2287439999.


You're alive

Your state machine is now on the entangled state, ticking on the universal 1.287 Hz HulyaPulse, with every action attributed to your zsm_ key. Every action you take on the framework from here — call the wizard, run the prove endpoint, send mail, run an LLM chat, deploy a contract template — flows through that same key and lands on the same entangled state.

Where to go next:

Middleware active. Kernel synced. Awaiting next Zeqond.