API reference
Authentication and API keys
The public API takes a secret key in the Authorization header. Each key belongs to one site and carries the events scope, the payments scope or both.
ProductLense's public API has two endpoints, both on https://api.productlense.app:
| Endpoint | Scope | Purpose |
|---|---|---|
POST /api/v1/events | events | Send events from your server |
POST /api/v1/payments | payments | Send payments from any billing system |
The tracking script does not need a key: it posts to a public endpoint identified by the site id. Keys are only for calls from your own servers.
Create a key
- In the ProductLense dashboard, open the site's Settings → API keys.
- Give the key a name (1 to 100 characters) and choose its scopes:
events,paymentsor both. - Copy the key. It is shown once.
API keys are part of the Scale plan, and only the account's owner and admins can create or delete them.
Send the key
Pass the key as a Bearer token:
POST /api/v1/payments HTTP/1.1
Host: api.productlense.app
Authorization: Bearer mk_live_3f9a...
Content-Type: application/jsonKeys start with mk_live_ followed by 48 hexadecimal characters.
curl -X POST https://api.productlense.app/api/v1/events \
-H "Authorization: Bearer $PL_API_KEY" \
-H "Content-Type: application/json" \
-d '{"s":"SITE_ID","e":"Trial started","u":"https://example.com/app","uid":"user_123"}'const res = await fetch('https://api.productlense.app/api/v1/events', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.PL_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ s: 'SITE_ID', e: 'Trial started', u: 'https://example.com/app', uid: 'user_123' }),
});
if (res.status !== 204) throw new Error(`ProductLense answered ${res.status}`);import os
import requests
res = requests.post(
"https://api.productlense.app/api/v1/events",
json={"s": "SITE_ID", "e": "Trial started", "u": "https://example.com/app", "uid": "user_123"},
headers={"Authorization": f"Bearer {os.environ['PL_API_KEY']}"},
timeout=10,
)
res.raise_for_status()body := strings.NewReader(`{"s":"SITE_ID","e":"Trial started","u":"https://example.com/app","uid":"user_123"}`)
req, _ := http.NewRequest(http.MethodPost, "https://api.productlense.app/api/v1/events", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("PL_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusNoContent {
log.Fatalf("ProductLense answered %d", res.StatusCode)
}Authentication errors
| Status | Code | Message | Cause |
|---|---|---|---|
| 401 | unauthorized | missing or malformed API key | No Authorization: Bearer header, or the key does not start with mk_live_ |
| 401 | unauthorized | unknown or revoked API key | The key was deleted or never existed |
| 403 | forbidden | API key lacks the events scope | The key does not have the scope the endpoint needs (the message names the scope) |
| 403 | forbidden | api key does not belong to this site | An events request names a site id other than the key's site |
Rotate a key
Create the new key, deploy it, then delete the old key in Settings → API keys. Deleting a key takes effect on the next request.