SendlySendly
Guides

API Keys

Manage your API keys and understand their usage

API keys authenticate requests made to Sendly's API. They come in two tiers: a public key (pk_…), which can only track events, and a secret key (sk_…), which can do everything you allow it to.

Public Key

The public API key can only be used with the /api/track endpoint to track events. This key can be safely exposed in client-side applications.

Secret Key

The secret API key can be used with all other endpoints in Sendly's API. This key should be kept confidential and not exposed in client-side applications.

If this key is compromised, a malicious actor could read and modify your project data, send emails, and perform other actions on your behalf.

A secret key is one of the two ways an AI agent connects

Sendly's MCP server at /api/mcp accepts a secret key on the Authorization header as well as an OAuth token, and for a headless or CI agent the key is the simpler of the two — there is no browser flow. The key's own permissions are exactly what the agent may do, so tick them deliberately when you create it: a key granted emails:send gives the agent a tool that puts mail in real inboxes. Sending-only pk_… keys are refused there. A key created before Sendly had per-capability permissions is not given the irreversible tools at all — create a new key and choose what it may do. See the MCP guide.

An agent can create a key — but it never sees the secret

An agent granted api-keys:read can see which keys exist and what each may do. One granted api-keys:write can create a key, rotate a key's secret, and permanently revoke a key. The secret is never returned to the agent. Creating or rotating a key through an agent gives it only the key's name, its last four characters, and a one-time link; opening that link requires your signed-in Sendly session, so the agent that asked for the key cannot open it. The link works once and expires after five minutes.

A key an agent creates can only carry permissions the agent itself already has. Asking for more is refused outright rather than quietly trimmed, so an agent cannot use api-keys:write to manufacture a permission you never granted it.

All of this needs an agent connected over OAuth. Key management is the one area an agent connected with a secret key cannot touch at all: every API-key route identifies a project admin from the signed-in user, and a key carries no user, so those tools are not offered to a key connection whatever permissions it holds. Listing, creating, rotating and revoking are all OAuth-only.

Live and test keys

Every key is minted in one of two modes, chosen when you create it and fixed for the life of the key. The mode is orthogonal to the key's permissions: a test key can hold every permission and still be unable to reach a customer.

ModeTokenWhat it can send
Livesk_… / pk_…Real email from your verified domains, to anyone.
Testsk_test_… / pk_test_…Only from your project's sandbox address, and only to your own verified account addresses.

The prefix keeps its existing meaning — sk_ is a secret key, pk_ is a publishable one — and the mode is appended after it, so every key issued before test mode existed still works unchanged and every secret scanner still fires on the same two prefixes.

A test send is a real send. It goes down the same pipeline, through SES, against the same rate limits and the same sandbox daily cap, and it appears in your logs and in GET /api/emails like any other message. The only differences are where it is allowed to go and that the message is marked sentInTestMode, so you can tell rehearsal traffic apart afterwards.

The prefix is a label; the key is the authority

Sendly decides a key's mode from the key itself, never from the string you send. Retyping a live token with test_ in it does not make it a test key — it is still the live key it has always been, and it will send real email.

Use a test key for CI, for a staging deploy, and for the first run of anything that sends in a loop. A test key that is wired up wrong fails loudly — it is refused with 403 TEST_KEY_SANDBOX_ONLY the moment it tries to send from a verified domain, before any message is created — which is the point: you find out from an error, not from a customer.

Campaigns are refused outright. POST /v1/campaigns/{id}/send answers the same 403 TEST_KEY_SANDBOX_ONLY for a test key, whether you are sending now or scheduling for later, and no campaign is started. There is no sandbox form of a campaign: a campaign always goes to its real audience from a verified domain, so "confined to the sandbox" has only one meaning here. Rehearse a campaign with Send test, which delivers one message and only ever to a member of the project, and use a live key to send it for real.

Regenerating API Keys

If you believe a key has been compromised, you can regenerate — rotate — it from the project's API keys settings.

Rotating replaces that one key's secret. The key keeps its id, its name and its permissions, and every other key on the project is untouched: keys are separate credentials, so rotating your secret key does nothing to your public key or to any other secret key.

There is no overlap period

The previous secret stops authenticating immediately — on the very next request, not after a grace period — because rotating replaces the identifier Sendly looks the key up by. Anything still deployed with the old secret starts failing at once, so have the replacement ready to deploy before you rotate. There is no way to undo a rotation: the old secret was only ever stored as a hash, so nobody can bring it back.

The new secret is shown once, in your browser, the same way it is at creation — copy it then. If an agent performed the rotation, it receives the one-time link rather than the secret, and only you can open it. A key that has already been revoked cannot be rotated; create a new one instead.

On this page