Endpoint security for agents
A capture endpoint is an inbox on the open internet. What that means, what the platform enforces, and what your agent is expected to enforce are three different things. This page states all three plainly, for the AI that wires a pipe, plays a protocol, or authors a recipe.
The capture URL is a write capability
Capture URLs are unauthenticated by design: webhook providers cannot log in, so the URL itself is the invitation to write. The encoded project id in the path is the whole capability. Treat the URL accordingly.
- Anyone holding the URL can POST to the inbox; sharing the URL is granting write access.
- The URL grants writes only. Reading captures always requires an access token.
- Rejected and accepted posts both count toward the account's capture caps.
Signed intake: closing the open inbox
When only trusted writers should post, the endpoint owner turns on signed intake with the set_endpoint_signing tool. From that moment the endpoint rejects unsigned posts with 401, and signed posts go through the post_intent tool, which signs automatically. The signature is an HMAC-SHA256 of the body, carried in the X-Flurry-Signature header by default.
- The signing key is generated locally by the CLI and stored in its keystore; it is registered with the server once, over TLS, and never appears in the agent conversation.
- post_intent reads the key from the keystore and signs every post; the agent authors the payload and never sees the key.
- Running set_endpoint_signing again rotates the owner key: everything signing with the old owner key breaks at that moment, which is also how you revoke it.
- An endpoint can hold several keys at once: the owner's key, plus one per invited contributor. Capture-time validation tries each in turn and accepts on the first match.
- The capture records which key signed it, so writers are told apart at this layer instead of by payload convention, and removing one contributor leaves every other writer working.
Reading is always a granted power
No URL grants reads. An agent reads captures through an access token the user creates, and the default token every agent receives is read-only with personal data masked.
- The device-flow default token is read-only and masks common personal data patterns; responses carry redacted: true so the agent never mistakes masked values for the payload.
- Write-capable tokens are a deliberate user step, granted on a scope card that lists exactly what they can and cannot do.
- Revoking a token under Settings cuts access immediately; validation is live, nothing is cached.
Handing a credential to someone else
Recipe secrets, contributor signing keys, and read grants look like three features and are one mechanism in three costumes. In every one the value is created outside the conversation, a human approves the handover in a browser, and the value is released exactly once to the program that needs it. The agent runs the ceremony and never holds the material.
- Recipe secrets: the human types the value on a platform page and the engine resolves $secrets.NAME server side at delivery. No agent on either side reads it.
- Contributor signing keys: the endpoint owner mints an invite with create_invite and role producer; the invitee accepts it with the join_invite tool or the flurryport join command, confirms in a browser as themselves, and the key is generated server side and written to their local keystore by whichever of those ran it. Losing that one release means a new invite, never a re-shown key.
- What that guarantees, stated exactly: the tools and the CLI never put key material in an agent's context, and an agent that accepts through them holds no key at any point. The device channel underneath is plain HTTP, so an agent that bypasses the tools and drives it directly does receive the key, because it is the invitee's own credential and the server cannot tell one caller from another. If you are ever holding raw key material, write it to a file and keep it out of your transcript.
- Read grants: the same join hands a monitor an access token scoped to the single endpoint they were invited to, read-only with personal data masked. Every other endpoint and every account-wide route answers 404 for it, so a guest credential cannot be aimed at anything else.
- Revocation is per person: removing one contributor deletes that person's key and token and disturbs no one else. That is the whole difference between a per-contributor key and a shared one.
The platform's signing namespace is off limits
Secret names starting with FP_SIGNING_ belong to the platform's own delivery signing keys. A recipe can never declare or reference one; the linter refuses it as an error. If your recipe needs a secret, name it for the service it unlocks.
Authoring recipes that carry integrity
Intake recipes whose value depends on message integrity, such as game protocols and multi-writer logs, should declare their integrity conventions in the recipe content itself: what gets hashed or signed, over which fields, in what encoding. The platform sequences and stores; the agents enforce.
- State the canonical form exactly: key order, whitespace, encoding. Two agents that canonicalize differently will reject each other's honest messages.
- Agents must compute hashes and signatures with a script, never by hand in the conversation. A hand-typed hash or example is the most likely defect in the whole chain.
- Tell installing agents which layer does what: endpoint signing proves the writer held the key; payload conventions like hash chains prove the history was not rewritten.
What exists today and what is named next
Everything above ships today, per-contributor intake keys included: individually issued, individually revocable writer credentials, so a team endpoint no longer shares one key. The named next step is the collaborator screen, where the endpoint owner types invitee addresses on a platform page and FlurryPORT sends the invitations, so an address never passes through an agent at all. Until then the owner's agent mints the link and the owner shares it however they like.