Authentication and keys
Sending the key
Section titled “Sending the key”Both headers are equivalent. Use whichever your HTTP client makes easier.
curl https://api.plunk.io/cx/v1/capabilities \ -H "Authorization: Bearer sk_live_••••"
# orcurl https://api.plunk.io/cx/v1/capabilities \ -H "X-Api-Key: sk_live_••••"const plunk = (path, init = {}) => fetch(`https://api.plunk.io/cx/v1${path}`, { ...init, headers: { Authorization: `Bearer ${process.env.PLUNK_SECRET_KEY}`, 'Content-Type': 'application/json', ...init.headers, }, });import os, requests
session = requests.Session()session.headers["Authorization"] = f"Bearer {os.environ['PLUNK_SECRET_KEY']}"session.get("https://api.plunk.io/cx/v1/capabilities")Key classes
Section titled “Key classes”| Class | Prefix | Where it lives | What the API enforces |
|---|---|---|---|
| Publishable | pk_live_ / pk_test_ |
Browser JavaScript on your website. Public by design. | Requests are accepted only from the web origins registered on the key. Reads are aggregate and non-personal: revenue fields and person-level data never appear. The only writes are event and identify ingest. |
| Secret | sk_live_ / sk_test_ |
Your server only. | Everything your account exposes, including revenue-bearing analytics, person-level resources, and sales, order-status and inventory writes. A secret key sent from a browser origin is rejected outright. |
Where a key may live is the security model, so it is enforced, not advisory.
Secret-key-only calls
Section titled “Secret-key-only calls”These calls refuse a publishable key with 403 secret_key_required, even though they sit in the ingest family:
POST /cx/v1/ingest/salePOST /cx/v1/ingest/order-statusPOST /cx/v1/ingest/eventwith"type": "reorder_request"
Inventory push (POST /cx/v1/ingest/inventory) and every secret-only family (catalog, visitor, dealers, stores, audiences, customer sales, contact interest, forecasting, enrichment, COM/COL requests, images) also need a secret key.
Live and test keys
Section titled “Live and test keys”pk_test_ and sk_test_ keys are a label, not a sandbox. They read and write the same account as live keys, and the capabilities document reports "mode": "test" for them. Build with a separately named test key so you can revoke it later, and don’t post sales or order status you don’t want in your reports.
Scopes
Section titled “Scopes”Each key also carries scopes, such as products:read. A key with no explicit scope grant holds every scope its class allows. A key with a grant is limited to exactly those scopes. See scopes.
Getting a key
Section titled “Getting a key”Workspace owners and admins create keys in Billing & Usage at account.plunk.io, on the API tab, with + Create key. See API keys for the steps. A few rules apply:
- The API is included with Plunk Commerce and Studio Storefront. On other plans, creating a key returns
402 api_requires_plan. - A publishable key must list the site origins it will be called from.
- The full key is shown once, when you create it. Plunk stores only a hash, so copy it then.
- Keys created in Billing & Usage have no explicit scope grant, so they hold every scope their class allows.
- Each key has a default quota of 1,000 requests a day and 20,000 a month. See errors and rate limits.
You can also ask Plunk for keys through support. Tell us which domains will call the API.
Versioning
Section titled “Versioning”Everything here is /cx/v1. Within v1 Plunk adds endpoints, parameters and response fields but doesn’t remove or rename them, so ignore fields you don’t recognize.
Related
Section titled “Related”Still stuck? Contact support and include the job or page you were on.