Epure
ProductSettings

Settings

Workspace settings (you / team) and project settings (DSN, retention, webhooks). Dashboard APIs need a session; Postgres RLS scopes rows with app.current_org_id.

How do I sign in?

Email and password at /login, or Google when GOOGLE_CLIENT_ID is set. Dashboard /api/v1/* needs the resulting cookie.

Billing tab

/billing applies to Epure Cloud workspaces only. Self-host operators can ignore it.

How do I open a session?

Password login returns 204 and Set-Cookie (Epure.sid on local HTTP). DSN headers on these routes return 401.

Sign in with email

Register at /login, or ./scripts/seed.sh --email … --password …. Never production.

command

curl -sS -c cookies.txt -D - -o /dev/null -X POST \
"http://localhost:8080/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"your-password"}'

Expected

HTTP/1.1 204 No Content
Set-Cookie: Epure.sid=...; HttpOnly; Path=/; SameSite=Lax
ResultWhat happenedWhat to do
204 + cookieSession establishedReuse -b cookies.txt on /api/v1/*
401Bad email or passwordRegister, or re-run seed with --email/--password
429 plain text20 login/register req / IP / 60sWait
Later 401 on /api/v1Cookie rejected (Secure vs HTTP)Local HTTP: EPURE_SESSION_SECURE=0. Troubleshooting

Full auth table: Authentication.

What is on workspace settings?

RoutePurpose
/settingsProfile / general account
/settings/securityPassword and sessions
/teamMembers, invites, roles
/usageUsage overview
/billingCloud subscription (Epure Cloud)

Sign-in at /login: email + password (argon2id), or Google when GOOGLE_CLIENT_ID is set.

Session cookies: Epure.sid on HTTP (EPURE_SESSION_SECURE=0), __Host-epure.sid behind HTTPS (EPURE_SESSION_SECURE=1).

Roles (RBAC lite)

RoleCan
OwnerEverything Admin can + delete projects, full workspace control
AdminProjects, DSN keys, webhooks, invites, project settings
MemberView and triage issues only

Invite by email from /team. Invitees register or sign in with Google; the assigned role applies on join.

SymptomWhat happenedWhat to do
Admin tabs read-onlySession role is MemberOwner/Admin invites you again with Admin
403 on DSN/webhook routesrequire_min_role(Admin) rejectedSign in as Admin or Owner
Invitee lands as MemberInvite carried MemberPatch role from /team as Owner/Admin

What is on project settings?

Base path: /p/:projectId/settings

TabRouteWho
General/p/:projectId/settingsAdmin / Owner
DSN keys/p/:projectId/settings/dsnAdmin / Owner
Webhooks/p/:projectId/settings/webhooksAdmin / Owner

DSN keys

Create, rotate, revoke. Revoked keys → ingest 403 dsn_revoked. UI walkthrough: Projects.

Create a DSN key

command

curl -sS -b cookies.txt -X POST \
"http://localhost:8080/api/v1/projects/${PROJECT_ID}/dsn-keys" \
-H "Content-Type: application/json" \
-d '{"label":"local-dev"}'

Expected

HTTP/1.1 201 Created

{ "id": "<key-uuid>", "project_id": "<project-uuid>", "public_key": "a1b2…", "label": "local-dev" }

Use public_key in the DSN copied from Settings → SDK connection. Official Sentry SDKs need that public key only.

Agent tokens

Personal access tokens for MCP (any stdio host) and epure-cli. Route: /settings/agent (Admin / Owner). When creating a token, enable optional checkboxes for write:triage and write:admin (full settings API).

ScopeAllows
read:agentRequired — all GET /api/v1/*
write:triageIssue/alert triage mutations
write:adminProjects, DSN, webhooks, alert rules, members, agent tokens

Tokens use prefix epure_pat_ and are shown once on create. Setup: MCP and epure-cli. HTTP: Agent API.

Create agent token

command

curl -sS -b cookies.txt -X POST \
"http://localhost:8080/api/v1/agent-tokens" \
-H "Content-Type: application/json" \
-d '{"label":"cursor","scopes":["read:agent","write:triage"]}'

Expected

HTTP/1.1 201 Created

{ "token": { "token": "epure_pat_…", "token_prefix": "…", "scopes": ["read:agent","write:triage"] } }

Revoke: POST /api/v1/agent-tokens/{id}/revoke.

Webhooks

Destinations: Slack (format: "slack"), Discord (discord), or custom HTTPS (generic).

Event idWhen
issue_createdFirst event for a fingerprint
regressionResolved issue returns in a newer release
velocity_spikeEvent rate jumped in the velocity window

URLs must be public HTTPS. Private/loopback targets require EPURE_WEBHOOK_ALLOW_PRIVATE=1 (dev/tests only).

Create a generic webhook

command

curl -sS -b cookies.txt -X POST \
"http://localhost:8080/api/v1/webhooks" \
-H "Content-Type: application/json" \
-d '{"project_id":"550e8400-e29b-41d4-a716-446655440000","url":"https://hooks.example.com/epure","format":"generic","events":["issue_created","regression"]}'

Expected

HTTP/1.1 201 Created

{ "id": "<webhook-uuid>", "url": "https://hooks.example.com/epure", "format": "generic", "events": ["issue_created","regression"], "signing_secret": "<shown once>" }

Test fire: POST /api/v1/webhooks/{id}/test with the same cookie → { "sent": true }. API reference: Webhooks.

ResultWhat happenedWhat to do
400 on createURL failed SSRF checks, or bad format/eventsPublic HTTPS; format in slack/discord/generic; events issue_created or regression
Hook never arrivesPrivate URL blockedDo not set EPURE_WEBHOOK_ALLOW_PRIVATE=1 in prod

How does RLS apply for operators?

  • Dashboard never trusts a client-supplied org id; membership on the session sets app.current_org_id
  • Ingest does not use the app RLS role; it authenticates by DSN and writes for that project
  • Three URLs: DATABASE_URL (migrations), EPURE_INGEST_DATABASE_URL, EPURE_APP_DATABASE_URL; see Configuration

Checklist

  • At least one Owner exists
  • Production uses HTTPS + EPURE_SESSION_SECURE=1
  • Public registration closed after the first account (EPURE_REGISTRATION=false)
  • DSN keys created; secrets stored outside git
  • CORS origins restricted (EPURE_CORS_ORIGINS) for browser SDKs
  • Webhooks pointed at public endpoints
  • Retention and ingest caps set per project
Why can a Member not rotate a DSN?

Rotate needs Admin or Owner; Members view and triage issues only. Ask an Owner to patch the role from /team. DSN create, rotate, and revoke sit on /p/:projectId/settings/dsn. Revoked keys then return 403 dsn_revoked on ingest.

Why is the Google button missing?

GOOGLE_CLIENT_ID is empty, so the login page hides Google. Set the id, secret, and a redirect URI matching {EPURE_PUBLIC_URL}/api/v1/auth/google/callback, then restart epure. Password login still works: Configuration.

Is a DSN the same as a session?

No. The DSN authenticates ingest only. Settings, Issues, and Events APIs use the login cookie and RLS. Sending DSN headers to /api/v1/* returns 401, and sending a cookie to envelope or store does nothing. See Authentication.

Next