---
title: "API reference"
description: "Call every Pug endpoint with plain JSON over HTTP POST. Base URLs, request format, auth modes and the Connect error model."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.pug.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# 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](/sdks) 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/Query
```

For Connect JSON (no generated client needed), send these headers on every request:

```http
Content-Type: application/json
Connect-Protocol-Version: 1
```

Add 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](/get-started/authentication).

### SDK key (`sdk.*` services)

Send your API key in the `x-api-key` header:

```http
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)

```http
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.

```http
x-api-key: prv_…          # server-side path
# — or —
Authorization: Bearer <jwt>   # dashboard path
```

### Public (no auth)

Two services require no credential:

- `public.auth.v1.AuthService` — sign-in, magic link, OAuth.
- `public.dashboards.v1.SharedDashboardsService` — reads a publicly-shared
  dashboard. Authorization comes from the unguessable **share token** carried in
  the request, so treat that token as a bearer credential: anyone holding it can
  read the dashboard.

### 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.*` | None | — (share token in the request body, where applicable) |

## Error model

All errors follow the Connect error envelope. For Connect JSON the response body is:

```json
{
  "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](/api/events) |
| Profiles (SDK) | `sdk.profiles.v1.ProfilesSDKService` | SDK key | [Profiles](/api/profiles) |
| Profiles (read/manage) | `shared.profiles.v1.ProfilesService` | Dual | [Profiles](/api/profiles) |
| Insights | `shared.insights.v1.InsightsService` | Dual | [Insights](/api/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 | — |
| Shared dashboards | `public.dashboards.v1.SharedDashboardsService` | None (share token) | — |

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](/reference/rpc-services).

## Next steps

- [Events](/api/events) — ingest events with `sdk.events.v1.EventsService/BatchCreate`
- [Profiles](/api/profiles) — identify users and read/manage profiles
- [Insights](/api/insights) — run analytics queries programmatically
- [HTTP transport](/sdks) — curl-ready plain-JSON recipes
- [RPC services](/reference/rpc-services) — full package and method map

Source: https://docs.pug.sh/api/index.mdx
