API Reference
You can call every endpoint with plain JSON over HTTP POST — two headers
(Content-Type: application/json and Connect-Protocol-Version: 1) plus a
JSON-encoded body. No client library or codegen is required; see
HTTP transport for a curl-ready recipe.
Under the hood the API is built on Connect RPC — a single set of handlers that speaks the Connect, gRPC, and gRPC-Web protocols over the same HTTP endpoints, on both HTTP/1.1 and HTTP/2. Generated clients are available for any language with Buf support, but the plain-JSON path above is all you need.
Base URL
| Environment | Base URL |
|---|---|
| Production | https://api.pugs.dev |
| Self-hosted / local | http://localhost:3000 |
The server port for self-hosted deployments defaults to 3000 (configurable via PUG_SERVER_PORT).
Request format
Every Connect RPC endpoint is reachable at:
POST /{package}.{Service}/{Method}For example:
POST /sdk.events.v1.EventsService/BatchCreate
POST /sdk.profiles.v1.ProfilesSDKService/Identify
POST /shared.insights.v1.InsightsService/QueryFor Connect JSON (no generated client needed), send these headers on every request:
Content-Type: application/json
Connect-Protocol-Version: 1Add the appropriate auth header (see below) and POST a JSON-encoded request body.
Authentication
Auth is enforced at the HTTP middleware layer, before any handler runs. The mode depends on the proto package. For obtaining and rotating keys, see Authentication.
SDK key (sdk.* services)
Send your API key in the x-api-key header:
x-api-key: pub_… # or prv_…Two key types are accepted:
| Key prefix | Access |
|---|---|
pub_… | Write / ingest only. Safe to embed in browser code via the Web SDK. |
prv_… | Full read-write. Server-side and trusted environments only. |
No Authorization header or x-project-id is required for SDK auth — the project
is resolved directly from the key.
Beacon requests (which cannot set headers) may pass a public key as the api_key
query parameter. Private keys are rejected on the query parameter path.
JWT (dashboard.* services)
Authorization: Bearer <jwt>Optionally add x-project-id: <project-id> to scope the request to a specific
project (the server verifies org membership). JWT auth is issued by public.auth.v1.AuthService.
Dual — private key or JWT (shared.* services)
Shared services are accessible from both server-side integrations and the dashboard.
The server checks x-api-key first; if absent, it falls back to Authorization: Bearer.
Only private keys (prv_…) are accepted via this path — public keys are rejected.
x-api-key: prv_… # server-side path
# — or —
Authorization: Bearer <jwt> # dashboard pathPublic (no auth)
public.auth.v1.AuthService (sign-in, magic link, OAuth) requires no credentials.
Auth matrix
| Proto package | Auth mode | Header |
|---|---|---|
sdk.* | SDK key | x-api-key: pub_… | prv_… |
dashboard.* | JWT | Authorization: Bearer <jwt> |
shared.* | Dual (private key or JWT) | x-api-key: prv_… or Authorization: Bearer <jwt> |
public.auth.v1 | None | — |
Error model
All errors follow the Connect error envelope. For Connect JSON the response body is:
{
"code": "invalid_argument",
"message": "events[0].name: value is required"
}Standard codes returned by the API (HTTP status is the Connect-protocol mapping):
| Code | HTTP status | Meaning |
|---|---|---|
unauthenticated | 401 | Missing, malformed, or expired credential |
permission_denied | 403 | Valid credential, insufficient access for this operation |
invalid_argument | 400 | Request failed protovalidate — fix the named field and retry |
not_found | 404 | Resource does not exist or is not visible to the caller |
already_exists | 409 | Attempted to create a resource that already exists |
failed_precondition | 412 | Operation rejected due to current system state |
resource_exhausted | 429 | Rate limit exceeded — back off and retry |
internal | 500 | Server-side error — retry with exponential backoff |
Connect errors also carry google.rpc.ErrorInfo details (reason + domain) and a
google.rpc.RequestInfo with the correlation id, useful for support requests.
Services at a glance
| Service | Proto name | Auth | Docs |
|---|---|---|---|
| Events (ingest) | sdk.events.v1.EventsService | SDK key | Events |
| Profiles (SDK) | sdk.profiles.v1.ProfilesSDKService | SDK key | Profiles |
| Profiles (read/manage) | shared.profiles.v1.ProfilesService | Dual | Profiles |
| Insights | shared.insights.v1.InsightsService | Dual | Insights |
| Activity | shared.activity.v1.ActivityService | Dual | — |
| Orgs | dashboard.orgs.v1.OrgsService | JWT | — |
| Projects | dashboard.projects.v1.ProjectsService | JWT | — |
| Dashboards | dashboard.dashboards.v1.DashboardsService | JWT | — |
| Customers | dashboard.customers.v1.CustomersService | JWT | — |
| Auth | public.auth.v1.AuthService | None | — |
Services showing — in the Docs column are dashboard or internal services not
covered in this reference. sdk.devices.v1.DevicesService handles push-notification
device registration and is likewise out of scope.
For the complete method index see RPC services.
Next steps
- Events — ingest events with
sdk.events.v1.EventsService/BatchCreate - Profiles — identify users and read/manage profiles
- Insights — run analytics queries programmatically
- HTTP transport — curl-ready plain-JSON recipes
- RPC services — full package and method map