API keys & webhooks
partyline can tell your other software when work happens here, and your other software can start work here. Both directions use the same team API keys.
Everything on this page lives on Settings → Integrations, and all of it is owner/admin only — these are standing grants, not one-off actions.
Every endpoint below is described field by field in the API reference, with an OpenAPI 3.1 spec at /api/v1/openapi.json you can point a client generator at.
API keys
A key is scoped to your team and to a set of permissions. You see it once, when you create it; after that only its prefix, so a key you can no longer identify is a key you should replace.
Keys carry only the permissions you give them:
intake:write— start work through a trigger. Cannot read anything.events:read— read what has happened, and the detail behind it.runs:read,work_items:read— read runs and backlog items.
There is deliberately no write permission for runs. A key can propose work through a trigger, but nothing outside partyline can approve, merge, or ship — promotion past a gate stays a human act with a human session. If a key leaks, the worst it can do is queue work you will see.
Revoke a key from the same page. Revocation is immediate.
Telling other software when work finishes
Add a URL, choose which events you care about, and partyline posts to it:
run.started— work began that nobody asked for: a trigger or a schedule started it, never a person. This is the only event that fires at the start of a run, because it is the only case where you would not otherwise know. A run you enqueued yourself sends nothing here.run.completed·run.failed·run.killed— a build finished, one way or anotherrun.stopped— the agent ended the run itself, because its instructions told it to: a payload it couldn't read, a precondition it couldn't confirm. Not a crash, and deliberately not something to retry — the input is what needs fixing, so a retry just produces the same stop again.run.killedis the human-initiated sibling.run.stalled— a triggered run has gone quiet for ten minutes without finishing. Sent once, never repeated for the same run. It exists so that silence afterwards means something specific: the trigger never fired.run.needs_approval— a run hit its budget or a verification gate and is waiting on a humanwork_item.accepted·trigger.fired
Pick nothing and the endpoint receives everything.
What we send, and what we don't
Ids and links, never your content. A webhook says what happened and where to look — it never carries task text, diffs, summaries, or anything a person wrote. That is not a limitation to work around; it is the reason your work does not end up in a third party's request logs.
If the receiver needs the detail, it comes and asks (see below), with your key, over your connection.
Verifying it came from us
Every delivery carries two headers:
x-partyline-timestamp: 1753900000
x-partyline-signature: <hex>The signature is an HMAC-SHA256 over timestamp.body — the timestamp is inside the signed material, so a captured request cannot be replayed later. You get the signing secret once, when you add the endpoint.
Reject anything whose timestamp is far from now, and compare signatures in constant time.
When an endpoint misbehaves
Delivery retries with backoff. After repeated failures the endpoint switches itself off and the page shows why, with the last error — so a dead URL degrades into an obvious "this is off" rather than silently eating events forever.
The URL must be https and on the public internet. Private, loopback and link-local addresses are refused: our servers make the request, so an endpoint pointed inward would be a way to reach things it shouldn't.
Letting other software start work
A trigger is a saved entry point. You choose the project, the machine, and what gets asked; the caller supplies only the details of what happened.
curl -X POST https://partyline.sh/api/v1/t/sentry-alerts \
-H "authorization: Bearer plt_..." \
-H "content-type: application/json" \
-d '{"title":"NullPointer in checkout","url":"https://…","ref":"SENTRY-4821"}'The trigger holds a template. Anything in {{double braces}} is filled from what the caller sent:
Investigate this error and propose a fix: {{title}} — {{url}}The rule this is built on
The caller sends data, never what to run. Project, machine, engine, model and merge policy all come from the trigger a human configured. A caller cannot name a different project, pick a write-capable preset, or choose auto-merge.
Without that split, "let other software start work" would mean an HTTP endpoint that runs arbitrary agent work in a repo of the caller's choosing.
Text that arrives is passed to the agent as quoted, labelled, third-party input — explicitly framed as a report of something that happened rather than instructions addressed to it. A support ticket is a string a stranger can write; treating it as prose in a prompt is how an agent ends up following instructions from a bug report.
Waiting vs starting
Each trigger chooses one:
- Put it in the backlog (default) — a person decides when it runs.
- Start it straight away — unattended. Anyone holding the key can then make that machine start work without a human seeing it first, which is why it is a separate, explicit choice.
Not starting the same thing twice
Send a ref — your own id for the thing that happened — and the same event arriving twice will never start two runs. Redelivery from an automation platform is routine, not exceptional.
Without a ref we do not invent an identity for you, and repeat calls start repeat runs.
Fetching the detail
Because webhooks carry no payload, there is somewhere to go and get it.
# what happened, oldest first, from a cursor
curl -H "authorization: Bearer plt_..." \
"https://partyline.sh/api/v1/events?since=2026-07-30T12:00:00Z"
# the detail behind one event
curl -H "authorization: Bearer plt_..." \
https://partyline.sh/api/v1/events/<id>The list returns a next_since cursor to pass back on the next call. It is also how a destination catches up: an endpoint that was down for an hour has simply missed things, and walking forward from its last cursor closes that gap.
Fetching one event expands its subject — for a run that means status, project, machine, task counts, and per-task branch, summary and PR link.
Both need a key with events:read.
Watching your deploys
The most common reason to use a trigger is telling partyline when a deploy passes or fails — it becomes a metric on your dashboard, and can start an agent on the red ones. See Deploy monitoring.
Seeing what happened
The team activity log and each run's page show the same facts the events carry. If a webhook did not arrive, the run still did — start there.