Skip to content

API Overview

Nametag exposes a JSON REST API covering everything the web app itself uses: people, groups, relationships, journal entries, the map, dashboard stats, CardDAV sync, and account settings. If you can do it in the UI, there’s almost always an API endpoint behind it.

All paths in this reference are relative to your Nametag instance:

https://your-instance.example.com

If you’re using the hosted service, that’s https://nametag.one. If you’re self-hosting, it’s whatever domain you’ve configured.

The API supports two authentication methods.

When you’re signed in through the browser, every request automatically carries the authjs.session-token cookie set by NextAuth.js. This is how the Nametag web app itself talks to the API. It’s not meant for external scripts since it requires a browser login flow, but it’s why the app “just works” without you thinking about tokens.

For scripts, integrations, and anything outside the browser, create a personal API token in Settings > API Tokens and send it as a bearer token:

Terminal window
curl https://your-instance.example.com/api/people \
-H "Authorization: Bearer ntag_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

API tokens work on nearly every endpoint that accepts a session cookie. The token management endpoints themselves (/api/user/api-tokens) are the one exception: creating and revoking tokens always requires a session, since letting a token manage other tokens would be a security hole. See API Tokens for scopes, expiry, and full examples.

Every response is JSON.

Successful responses return the resource, usually wrapped in a named key that matches the resource type:

{ "person": { "id": "clxyz...", "name": "Ada" } }

or, for list endpoints:

{ "people": [ { "id": "clxyz...", "name": "Ada" } ] }

Errors return an error field with a human-readable message:

{ "error": "Person not found" }

Validation failures (HTTP 400) additionally include a details array with per-field messages:

{
"error": "Validation failed",
"details": [
{ "field": "name", "message": "Name is required" }
]
}
StatusMeaning
200Success
201Resource created
400Bad request, usually a validation error
401Not authenticated, missing or invalid session/token
403Forbidden, valid auth but not allowed (e.g. a plan limit or a read-only token trying to write)
404Resource not found, or not owned by the authenticated user
409Conflict, e.g. trying to create a second CardDAV connection
413Payload too large, e.g. a vCard file over 2 MB
429Rate limited, see below
500Server error
503Service unavailable, used by the health check when the database is unreachable

Rate limiting applies to sensitive, unauthenticated endpoints, not to the general CRUD API. It protects things like login, registration, password reset, and CardDAV credential testing from brute-force abuse. Limits are IP-based sliding windows: for example, login allows 5 attempts per 15 minutes, and registration allows 3 attempts per hour.

Storage is Redis-backed in production when Redis is configured (falling back to an in-memory store per instance otherwise) and always in-memory in development. A 429 response includes a Retry-After header and a retryAfter field in seconds.

Everyday endpoints like /api/people or /api/groups are not rate-limited beyond your plan’s usage limits.

EndpointMax attemptsWindow
Login515 minutes
Register31 hour
Forgot password31 hour
Reset password51 hour
Resend verification315 minutes
Verify email1015 minutes
CardDAV test1015 minutes
CardDAV sync55 minutes
CardDAV backup515 minutes

The REST endpoints (/api/people, /api/groups, /api/relationships, /api/relationship-types) return the full collection in one response, since personal networks are typically a few hundred people at most rather than millions of rows. The one REST endpoint that paginates is journal entries.

The web app’s own list pages (which call these same endpoints and paginate client-side) use these page sizes:

ListPage size
Default page size (generic fallback used elsewhere in the app)20
Maximum page size allowed by any paginated view100
People page50 per page
Groups page24 per page
Journal50 per page

GET /api/journal accepts a page query parameter and returns a pagination object alongside the entries:

{
"entries": [ /* ... */ ],
"pagination": { "page": 1, "pageSize": 50, "totalCount": 132, "totalPages": 3 }
}

See Journal for details.

BodyLimit
Default API request body1 MB
JSON import5 MB
vCard import / upload2 MB
Photo upload50 MB

Requests over the applicable limit are rejected with 413 Payload Too Large.

The API also ships with self-documenting tools you can use alongside this reference:

  • Swagger UI at /api/docs, an interactive explorer where you can browse every endpoint and try requests against your own instance.
  • Raw OpenAPI spec at /api/openapi.json, the machine-readable source of truth this reference is generated from.

List the people in your network with an API token:

Terminal window
curl https://your-instance.example.com/api/people \
-H "Authorization: Bearer ntag_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
{
"people": [
{
"id": "clx1a2b3c",
"name": "Ada",
"surname": "Lovelace",
"organization": "Analytical Engine Society",
"groups": [],
"createdAt": "2026-01-15T10:00:00.000Z",
"updatedAt": "2026-01-15T10:00:00.000Z"
}
]
}