Surfaces (Ingest · Events)
The HTTP API is the request/response surface. Two more surfaces close the loop — so the agent can be fed from where product intent already lives, and can notify your systems when something happens.
Each is its own thin Worker or module on top of the same control plane. Nothing here is a second copy of the API — every surface funnels back through the same auth and logic.
Ingest (inbound)
Section titled “Ingest (inbound)”Register an ingest source and anything that can sign an HTTP request can post an idea into a project (which becomes a ticket) — so work flows in from wherever it already lives, instead of being re-entered by hand.
Create a source (session-only; returns the secret + URL once):
curl -X POST https://<your-api-host>/api/v1/ingest \ -H 'content-type: application/json' \ --cookie "$SESSION" \ -d '{ "projectId": "prj_…" }'# → { "ok": true, "data": { "id": "ing_…", "secret": "whsec_…",# "webhookUrl": "https://hooks.typillar.com/i/ing_…" } }POST a signed JSON body of { title, text, id?, url? } to webhookUrl. Requests
hit the ingress Worker (hooks.typillar.com), which verifies the signature and
hands the idea to the control plane. Reusing id returns the idea already
captured, so a retry cannot duplicate a ticket.
See Webhooks for the signature scheme, the status codes, idempotency, and verification code you can copy.
Events (outbound)
Section titled “Events (outbound)”Subscribe a webhook endpoint to lifecycle events and Typillar POSTs each one to your URL — so a deploy can notify Slack, or a build result can kick a downstream job.
curl -X POST https://<your-api-host>/api/v1/webhooks \ -H 'content-type: application/json' \ --cookie "$SESSION" \ -d '{ "url": "https://example.com/hook", "events": ["project.deployed","project.reverted"] }'# → { "ok": true, "data": { "id": "whe_…", "secret": "whsec_…" } }The event types, in full — use ["*"] for all of them:
| Event | Fires when |
|---|---|
project.created |
a project is created |
ticket.created |
a ticket is opened, however it arrived |
ticket.updated |
a ticket’s fields change |
ticket.build.succeeded |
a build finishes and produces an app |
ticket.build.failed |
a build fails |
project.deployed |
a Deployment goes live |
project.rolled_back |
a Deployment is rolled back — a live release taken off its URL |
project.reverted |
the code is restored to an earlier version |
project.renamed |
a project is renamed |
project.archived |
a project is archived — taken offline, its data kept |
project.deleted |
a project is deleted |
project.reverted is Restore and project.rolled_back is Roll back — different
acts, different events. See Webhooks.
Each POST carries a Typillar-Signature header and an EventEnvelope body:
{ "id": "evt_…", "type": "project.deployed", "projectId": "prj_…", "createdAt": 1751000000000, "data": { "url": "https://…" } }Every endpoint receives this same signed envelope. To forward events into a chat tool, post them on from your own handler.
Delivery is at-least-once and retried. See Webhooks
for verification code, the retry policy, and why you must deduplicate on
Typillar-Delivery-Id.
How it’s built
Section titled “How it’s built”All three surfaces funnel back through the same control plane, so each one enforces the same authentication, scopes, and validation as the HTTP API — there’s no weaker second door, and no rules to keep in sync across surfaces. Outbound event delivery is durable and retried, so a brief outage on your side doesn’t lose events.