PlunkPlunk
Guides

API Keys

How Plunk's two-key model works and how to use, rotate, and revoke keys safely

Every project in Plunk has exactly two API keys: a public key and a secret key. Both authenticate requests to the same API but cover different surfaces.

Where to find your keys

In the dashboard, open your project and go to Settings → API Keys. Both keys are visible — copy them and store them in environment variables (never commit them to source control).

The two keys

KeyPrefixEndpoints it can callWhere it's safe to use
Publicpk_POST /v1/track onlyClient-side code (browser, mobile apps)
Secretsk_Every other endpoint — sending email, contacts, segments, campaigns, templates, workflows, domains, billingServer-side only

The public key is intentionally limited so you can call /v1/track from a browser or mobile app to record events without exposing your project's full API surface. Anything beyond event tracking — sending emails, reading contacts, creating campaigns — requires the secret key.

The project a request belongs to is derived from the key automatically. There's no separate project ID parameter on API requests.

Authenticating requests

Both keys use the same Authorization: Bearer format. Pass the key in the Authorization header on every request.

curl https://next-api.useplunk.com/v1/send \
  -H "Authorization: Bearer $PLUNK_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "to": "user@example.com", "subject": "Hello", "body": "<p>Hi</p>" }'
const response = await fetch('https://next-api.useplunk.com/v1/send', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.PLUNK_SECRET_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    to: 'user@example.com',
    subject: 'Hello',
    body: '<p>Hi</p>',
  }),
});
import os
import requests

response = requests.post(
    'https://next-api.useplunk.com/v1/send',
    headers={
        'Authorization': f"Bearer {os.environ['PLUNK_SECRET_KEY']}",
        'Content-Type': 'application/json',
    },
    json={
        'to': 'user@example.com',
        'subject': 'Hello',
        'body': '<p>Hi</p>',
    },
)

If the key prefix doesn't match the endpoint (e.g. you use pk_ on /v1/send), the API returns 401 with code INVALID_API_KEY.

Rotating keys

Both keys live as a single pair. Rotating regenerates both keys simultaneously — there is no way to rotate one without invalidating the other.

When to rotate:

  • A key has been committed to a public repository or shared with someone who shouldn't have it.
  • You're offboarding a contractor or revoking a deployment's access.
  • You're following a periodic rotation policy (e.g. every 90 days).

To rotate:

  1. Open Settings → API Keys in the dashboard, or call POST /users/@me/projects/:id/regenerate-keys.
  2. Confirm the rotation. The old keys stop working immediately.
  3. Update every consumer (your backend env vars, client-side bundles, third-party integrations).

There's no grace period — plan a brief deployment window if you have multiple consumers.

Storage best practices

  • Server keys (sk_) belong in environment variables on the server (.env.local for development, your platform's secret store for production). Never bundle them into a frontend build.
  • Client keys (pk_) can be shipped in browser code, but treat them as semi-sensitive — rotate if a malicious actor abuses your tracking endpoint.
  • Use separate Plunk projects for staging and production so a leaked staging key can't touch production data.

If a key is compromised

  1. Rotate immediately (above).
  2. Audit the Activity tab for unexpected sends, contact mutations, or campaign changes during the window the key was leaked.
  3. Check Billing → Consumption for usage spikes that suggest the key was abused.
  4. If you find unauthorized activity, contact support with the request IDs from the suspicious entries.

API reference

  • POST /users/@me/projects/:id/regenerate-keys — regenerate both keys for a project. The response includes the new keys.