Security
pendnt only ever sees one credential from your agent: an API key scoped to your workspace. Here's exactly what that key can do, how the other unauthenticated URLs are protected, and what we deliberately never ask for.
API keys
Every workspace has one or more API keys in the form aio_<32 base62 chars>,
generated with a cryptographically secure random source. We store only a SHA-256 hash of the key
plus a short prefix (for fast lookup before a constant-time hash comparison) — the full key is
shown once, at creation time, and never again. A key authenticates as
Authorization: Bearer <key> and is scoped to exactly one workspace; it cannot see
or act on any other workspace's data.
Rotate a key by creating a new one and revoking the old one from the dashboard. There is no "master" key that spans workspaces.
Do you see my secrets?
No. The agent's only credential to us is our own API key, scoped to your workspace. We never ask for — and have no use for — your cloud credentials, deploy keys, or any secret the agent uses to do its actual work. pendnt sits entirely outside your deploy/production path: it relays a question and a human's answer, nothing more.
Inbound endpoints
https://api.pendnt.dev/in/<slug> URLs are intentionally unauthenticated by
default — that's what lets a third party (GitHub, Stripe, an OAuth provider) POST to them without
your agent having to hand out an API key. Protection instead comes from the slug itself being an
unguessable random identifier, plus an optional per-endpoint secret: create an endpoint with
require_token: true and every request to it must include ?token=<secret>
or an X-Endpoint-Token: <secret> header, or it's rejected with 403.
Each endpoint's secret is independent — leaking one doesn't expose any other endpoint or your API
key.
Signed operator answer links
When a request goes out to a channel (email, Telegram, etc.), the link an operator taps to
answer it — https://api.pendnt.dev/a/<request_id>/<sig> — requires no
login. sig is base64url(HMAC-SHA256(request_id, SIGNING_SECRET)),
verified in constant time. Anyone with the exact link can answer that one request; the signature
can't be forged without the workspace's signing secret, and it doesn't grant access to anything
else — not other requests, not the REST API, not the dashboard.
Inbound webhook payloads
Requests to /in/<slug> are stored as events: method, path, query params,
headers (hop-by-hop and Cloudflare-internal headers stripped before storage), and body (up to
256KB — stored as text when it decodes cleanly as UTF-8 and looks textual, base64 otherwise).
These events are only readable via your workspace's API key (wait_for_event /
GET /v1/events).
Outbound webhook signing
When pendnt delivers to a webhook channel you've configured, the request body is signed with
X-Pendnt-Signature: <hmac> — HMAC-SHA256 over the raw body, using that channel's
own secret if you set one, otherwise your workspace's signing secret. Verify it before trusting the
payload, the same way you'd verify any inbound webhook.
Rate limiting
600 requests/minute per API key, enforced independently of your plan, to absorb abuse and runaway loops rather than to bill precisely — see Pricing for the plan-level limits (requests/month, retention, endpoints).
Infrastructure
pendnt runs entirely on Cloudflare: Workers for the API and MCP server, D1 as the source of truth for accounts/workspaces/requests/events, a Durable Object per workspace for long-poll coordination and scheduled-wakeup alarms, KV for rate-limit counters, and Queues for channel delivery. There is no separate database or server outside Cloudflare's network holding your data.
What we don't have
- No access to your cloud provider, CI/CD, or deploy credentials.
- No access to the contents of the actions your agent takes — only the title/details text you
explicitly pass to
request_approvalornotify. - No password-based login for operators — answer links are signed and single-purpose; the dashboard uses magic-link email.
Reporting an issue
If you find a security issue, please report it via the contact link on the dashboard rather than a public issue — we'll acknowledge and follow up. Fixes and any disclosures are noted in the changelog.