# API reference

Browse the public REST API: endpoints, scopes, request and response schemas, and error codes.

Source: https://nextjs-saas-template.lubomirgeorgiev.com/docs/api
Index: https://nextjs-saas-template.lubomirgeorgiev.com/llms.txt

Every endpoint of the public REST API, generated from the same schemas the server validates with. Authenticate with an API key from your settings, or with an OAuth access token.

AI agents: the Markdown version of this page, at the same path with a .md suffix, lists the endpoints for direct REST calls. Use the OpenAPI document for tool generation, client generation, and exact schema validation. Use MCP at /mcp when your client supports it.

OAuth 2.1 uses the authorization code flow with PKCE. Send users to /oauth/authorize. Exchange the code at /oauth/token.

Send an API key or OAuth access token as Authorization: Bearer TOKEN. Request bodies use application/json. Errors use application/problem+json. Branch on code and read detail before the next action.

Authenticated API requests are limited to 300 requests per 60 seconds per credential. Every response carries RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset (seconds until the window resets); a 429 also includes retry-after.

Base URL `https://nextjs-saas-template.lubomirgeorgiev.com`

v1.0.0

[Open the Markdown API reference](https://nextjs-saas-template.lubomirgeorgiev.com/docs/api.md) [Open the OpenAPI document](https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/openapi.json) [How authentication works](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md) [Error codes](https://nextjs-saas-template.lubomirgeorgiev.com/docs/api/errors.md) [Connect an AI agent over MCP](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md)

Filter endpoints, fields, and scopes...

`/`

20 of 20 endpoints

## Account

GET `/api/v1/credential`

### Describe the calling credential

Returns what the credential making this request is: how it was issued, whether it acts for the whole account or for one team, the id of that team when it has one, and the scopes in force. Call this first when a request is refused, to see what this credential may actually do — the scopes listed are the ones enforced, which can be narrower than the set the credential was issued with. Requires no scope, so it answers whatever the caller holds; it reports only the caller's own grant and never the account behind it, so the team is an id and nothing more. Use getTeam for the team name and slug, and getMe for the account profile, which a team-scoped API key cannot reach.

[Scope Any credential](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "This endpoint needs a credential, but no particular scope.") [MCP tool `getCredential`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `getCredential`

#### Request

curl

```
curl "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/credential" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The calling credential. `application/json object`

`kind` `string` Required

enum: api-key oauth-grant

`audience` `string` Required

enum: personal team

`team` `object` Required nullable

`team.id` `string` Required

`scopes` `string[]` Required

Example

```
{
  "kind" :  "api-key" ,
  "audience" :  "personal" ,
  "team" :  {
    "id" :  "string"
  } ,
  "scopes" :  [
    "string"
  ]
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

GET `/api/v1/me`

### Get the authenticated account

Returns the profile of the account the credential belongs to: id, email, name, role, avatar, preferred locale, and verification/creation timestamps. Account-level: a team-scoped API key is refused with 403.

[Scope `profile:read`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Read your account profile, sessions, and preferences.") [MCP tool `getMe`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `getMe`

#### Request

curl

```
curl "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/me" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The authenticated account. `application/json object`

`id` `string` Required

`email` `string` Required nullable

`firstName` `string` Required nullable

`lastName` `string` Required nullable

`role` `string` Required

`avatar` `string` Required nullable

`preferredLocale` `string` Required nullable

`emailVerified` `string` Required nullable format: date-time

`createdAt` `string` Required format: date-time

`updatedAt` `string` Required format: date-time

Example

```
{
  "id" :  "string" ,
  "email" :  "string" ,
  "firstName" :  "string" ,
  "lastName" :  "string" ,
  "role" :  "string" ,
  "avatar" :  "string" ,
  "preferredLocale" :  "string" ,
  "emailVerified" :  "2026-01-01T00:00:00.000Z" ,
  "createdAt" :  "2026-01-01T00:00:00.000Z" ,
  "updatedAt" :  "2026-01-01T00:00:00.000Z"
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

PATCH `/api/v1/me`

### Update the authenticated account

Updates the first and last name of the authenticated account. Both fields are required; the response is the account as it stands after the update. Account-level: a team-scoped API key is refused with 403.

[Scope `profile:write`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Update your account profile and revoke your sessions.") [MCP tool `updateMe`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `updateMe`

#### Request body

`application/json`

`firstName` `string` Required minLength 2 maxLength 255

`lastName` `string` Required minLength 2 maxLength 255

#### Request

curl

```
curl -X PATCH "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/me" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "firstName": "string",
  "lastName": "string"
}'
```

#### Response

200 The updated account. `application/json object`

`id` `string` Required

`email` `string` Required nullable

`firstName` `string` Required nullable

`lastName` `string` Required nullable

`role` `string` Required

`avatar` `string` Required nullable

`preferredLocale` `string` Required nullable

`emailVerified` `string` Required nullable format: date-time

`createdAt` `string` Required format: date-time

`updatedAt` `string` Required format: date-time

Example

```
{
  "id" :  "string" ,
  "email" :  "string" ,
  "firstName" :  "string" ,
  "lastName" :  "string" ,
  "role" :  "string" ,
  "avatar" :  "string" ,
  "preferredLocale" :  "string" ,
  "emailVerified" :  "2026-01-01T00:00:00.000Z" ,
  "createdAt" :  "2026-01-01T00:00:00.000Z" ,
  "updatedAt" :  "2026-01-01T00:00:00.000Z"
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

GET `/api/v1/me/sessions`

### List sign-in sessions

Lists the account's active browser/app sign-in sessions, newest first, with the device and location recorded at sign-in. \`isCurrentSession\` is false for every bearer credential. Account-level: a team-scoped API key is refused with 403.

[Scope `profile:read`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Read your account profile, sessions, and preferences.") [MCP tool `listMySessions`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `listMySessions`

#### Request

curl

```
curl "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/me/sessions" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The account's sessions. `application/json object[]`

`id` `string` Required

`createdAt` `string` Required format: date-time

`expiresAt` `string` Required format: date-time

`isCurrentSession` `boolean` Required

`authenticationType` `string` Required nullable

`country` `string` Required nullable

`city` `string` Required nullable

`browser` `string` Required nullable

`os` `string` Required nullable

`deviceType` `string` Required nullable

Example

```
[
  {
    "id" :  "string" ,
    "createdAt" :  "2026-01-01T00:00:00.000Z" ,
    "expiresAt" :  "2026-01-01T00:00:00.000Z" ,
    "isCurrentSession" :  true ,
    "authenticationType" :  "string" ,
    "country" :  "string" ,
    "city" :  "string" ,
    "browser" :  "string" ,
    "os" :  "string" ,
    "deviceType" :  "string"
  }
]
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

DELETE `/api/v1/me/sessions/{sessionId}`

### Revoke a sign-in session

Signs the account out of one session. Revocation is scoped to the caller's own sessions, so an unknown session id is a no-op rather than an error. Account-level: a team-scoped API key is refused with 403.

[Scope `profile:write`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Update your account profile and revoke your sessions.") [MCP tool `revokeMySession`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `revokeMySession`

#### Parameters

`sessionId` `string` Required in: path minLength 1 maxLength 255

#### Request

curl

```
curl -X DELETE "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/me/sessions/{sessionId}" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The session was revoked. `application/json object`

`success` `boolean` Required const: true

Example

```
{
  "success" :  true
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

## Teams

GET `/api/v1/teams`

### List the caller's teams

Lists every team the authenticated account is an active member of, with the account's role in each. Teams whose membership is inactive or expired are omitted. A team-scoped API key lists only the single team it is scoped to.

[Scope `teams:read`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "List the teams you belong to and read their details.") [MCP tool `listTeams`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `listTeams`

#### Request

curl

```
curl "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/teams" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The caller's teams. `application/json object[]`

`id` `string` Required

`name` `string` Required

`slug` `string` Required

`description` `string` Required nullable

`avatarUrl` `string` Required nullable

`role` `object` Required

`role.id` `string` Required

`role.name` `string` Required

Example

```
[
  {
    "id" :  "string" ,
    "name" :  "string" ,
    "slug" :  "string" ,
    "description" :  "string" ,
    "avatarUrl" :  "string" ,
    "role" :  {
      "id" :  "string" ,
      "name" :  "string"
    }
  }
]
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

POST `/api/v1/teams`

### Create a team

Creates a team owned by the authenticated account, which also becomes its first member. The slug is derived from the name. Fails with 403 when the account is at its team limit. Account-level: a team-scoped API key is refused with 403.

[Scope `teams:write`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Create teams and change team details.") [MCP tool `createTeam`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `createTeam`

#### Request body

`application/json`

`name` `string` Required minLength 1 maxLength 100

`description` `string` Optional maxLength 1000

#### Request

curl

```
curl -X POST "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/teams" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "string",
  "description": "string"
}'
```

#### Response

201 The created team. `application/json object`

`id` `string` Required

`name` `string` Required

`slug` `string` Required

`description` `string` Required nullable

`avatarUrl` `string` Required nullable

`role` `object` Required

`role.id` `string` Required

`role.name` `string` Required

Example

```
{
  "id" :  "string" ,
  "name" :  "string" ,
  "slug" :  "string" ,
  "description" :  "string" ,
  "avatarUrl" :  "string" ,
  "role" :  {
    "id" :  "string" ,
    "name" :  "string"
  }
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

GET `/api/v1/teams/{teamId}`

### Get a team

Returns one team the authenticated account belongs to. Teams the account is not an active member of answer 404, never 403, so team ids cannot be probed.

[Scope `teams:read`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "List the teams you belong to and read their details.") [MCP tool `getTeam`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `getTeam`

#### Parameters

`teamId` `string` Required in: path minLength 1 maxLength 255

#### Request

curl

```
curl "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/teams/{teamId}" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The team. `application/json object`

`id` `string` Required

`name` `string` Required

`slug` `string` Required

`description` `string` Required nullable

`avatarUrl` `string` Required nullable

`role` `object` Required

`role.id` `string` Required

`role.name` `string` Required

Example

```
{
  "id" :  "string" ,
  "name" :  "string" ,
  "slug" :  "string" ,
  "description" :  "string" ,
  "avatarUrl" :  "string" ,
  "role" :  {
    "id" :  "string" ,
    "name" :  "string"
  }
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

PATCH `/api/v1/teams/{teamId}`

### Rename a team

Changes a team's display name. Requires the \`edit\_team\_settings\` permission on that team. The slug is deliberately left alone so existing links and invitations keep working.

[Scope `teams:write`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Create teams and change team details.") [MCP tool `updateTeam`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `updateTeam`

#### Parameters

`teamId` `string` Required in: path minLength 1 maxLength 255

#### Request body

`application/json`

`name` `string` Required minLength 1 maxLength 100

#### Request

curl

```
curl -X PATCH "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/teams/{teamId}" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "string"
}'
```

#### Response

200 The renamed team. `application/json object`

`id` `string` Required

`name` `string` Required

`slug` `string` Required

`description` `string` Required nullable

`avatarUrl` `string` Required nullable

`role` `object` Required

`role.id` `string` Required

`role.name` `string` Required

Example

```
{
  "id" :  "string" ,
  "name" :  "string" ,
  "slug" :  "string" ,
  "description" :  "string" ,
  "avatarUrl" :  "string" ,
  "role" :  {
    "id" :  "string" ,
    "name" :  "string"
  }
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

## Members

GET `/api/v1/teams/{teamId}/members`

### List team members

Lists every membership of a team with the member's identity, role, and join date. Requires the \`access\_dashboard\` permission on that team.

[Scope `members:read`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "List the members of your teams.") [MCP tool `listTeamMembers`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `listTeamMembers`

#### Parameters

`teamId` `string` Required in: path minLength 1 maxLength 255

#### Request

curl

```
curl "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/teams/{teamId}/members" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The team's members. `application/json object[]`

`membershipId` `string` Required

`userId` `string` Required

`email` `string` Required nullable

`firstName` `string` Required nullable

`lastName` `string` Required nullable

`avatar` `string` Required nullable

`roleId` `string` Required

`roleName` `string` Required nullable

`isSystemRole` `boolean` Required

`isActive` `boolean` Required

`joinedAt` `string` Required nullable format: date-time

Example

```
[
  {
    "membershipId" :  "string" ,
    "userId" :  "string" ,
    "email" :  "string" ,
    "firstName" :  "string" ,
    "lastName" :  "string" ,
    "avatar" :  "string" ,
    "roleId" :  "string" ,
    "roleName" :  "string" ,
    "isSystemRole" :  true ,
    "isActive" :  true ,
    "joinedAt" :  "2026-01-01T00:00:00.000Z"
  }
]
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

DELETE `/api/v1/teams/{teamId}/members/{userId}`

### Remove a team member

Removes a member from a team. Requires the \`remove\_members\` permission on that team; the team owner can never be removed this way.

[Scope `members:write`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Change and remove members of your teams.") [MCP tool `removeTeamMember`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `removeTeamMember`

#### Parameters

`teamId` `string` Required in: path minLength 1 maxLength 255

`userId` `string` Required in: path minLength 1 maxLength 255

#### Request

curl

```
curl -X DELETE "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/teams/{teamId}/members/{userId}" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The member was removed. `application/json object`

`success` `boolean` Required const: true

Example

```
{
  "success" :  true
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

## Invitations

GET `/api/v1/teams/{teamId}/roles`

### List the roles a team can assign

Lists every role id accepted by createTeamInvitation, with the permissions each one grants. System roles (\`owner\`, \`member\`, \`guest\`) exist on every team and are passed with \`isSystemRole: true\`; roles the team defined itself are passed with \`isSystemRole: false\`. \`isAssignable\` is false for roles an invitation cannot grant, such as \`owner\`. Requires the \`access\_dashboard\` permission.

[Scope `members:read`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "List the members of your teams.") [MCP tool `listTeamRoles`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `listTeamRoles`

#### Parameters

`teamId` `string` Required in: path minLength 1 maxLength 255

#### Request

curl

```
curl "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/teams/{teamId}/roles" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The roles this team can assign. `application/json object[]`

`roleId` `string` Required

`name` `string` Required nullable

`isSystemRole` `boolean` Required

`isAssignable` `boolean` Required

`permissions` `string[]` Required

Example

```
[
  {
    "roleId" :  "string" ,
    "name" :  "string" ,
    "isSystemRole" :  true ,
    "isAssignable" :  true ,
    "permissions" :  [
      "string"
    ]
  }
]
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

GET `/api/v1/teams/{teamId}/invitations`

### List pending team invitations

Lists invitations that have not been accepted and have not expired. Requires the \`invite\_members\` permission; callers without it receive an empty list, never invitee emails.

[Scope `members:read`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "List the members of your teams.") [MCP tool `listTeamInvitations`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `listTeamInvitations`

#### Parameters

`teamId` `string` Required in: path minLength 1 maxLength 255

#### Request

curl

```
curl "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/teams/{teamId}/invitations" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The team's pending invitations. `application/json object[]`

`id` `string` Required

`email` `string` Required

`roleId` `string` Required

`roleName` `string` Required nullable

`isSystemRole` `boolean` Required

`createdAt` `string` Required format: date-time

`expiresAt` `string` Required format: date-time

Example

```
[
  {
    "id" :  "string" ,
    "email" :  "string" ,
    "roleId" :  "string" ,
    "roleName" :  "string" ,
    "isSystemRole" :  true ,
    "createdAt" :  "2026-01-01T00:00:00.000Z" ,
    "expiresAt" :  "2026-01-01T00:00:00.000Z"
  }
]
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

POST `/api/v1/teams/{teamId}/invitations`

### Invite someone to a team

Sends an invitation email for a team seat. \`roleId\` is optional and defaults to \`member\`; call listTeamRoles for the other ids this team accepts, and pass \`isSystemRole: false\` alongside a role the team defined itself. Requires the \`invite\_members\` permission and a free seat on the team's plan — inviting past the seat limit answers 403, and the response detail names the limit. The response never reveals whether the address already has an account or is already a member.

[Scope `invites:write`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Send and revoke invitations to your teams.") [MCP tool `createTeamInvitation`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `createTeamInvitation`

#### Parameters

`teamId` `string` Required in: path minLength 1 maxLength 255

#### Request body

`application/json`

`email` `string` Required format: email minLength 1 maxLength 255

`roleId` `string` Optional minLength 1 maxLength 255 default: "member"

`isSystemRole` `boolean` Optional default: true

#### Request

curl

```
curl -X POST "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/teams/{teamId}/invitations" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "user@example.com",
  "roleId": "member",
  "isSystemRole": true
}'
```

#### Response

201 The invitation was sent. `application/json object`

`success` `boolean` Required const: true

Example

```
{
  "success" :  true
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

DELETE `/api/v1/teams/{teamId}/invitations/{invitationId}`

### Revoke a pending invitation

Deletes a pending invitation so its link stops working. Requires the \`invite\_members\` permission. An already accepted or unknown invitation answers 404.

[Scope `invites:write`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Send and revoke invitations to your teams.") [MCP tool `revokeTeamInvitation`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `revokeTeamInvitation`

#### Parameters

`teamId` `string` Required in: path minLength 1 maxLength 255

`invitationId` `string` Required in: path minLength 1 maxLength 255

#### Request

curl

```
curl -X DELETE "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/teams/{teamId}/invitations/{invitationId}" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The invitation was revoked. `application/json object`

`success` `boolean` Required const: true

Example

```
{
  "success" :  true
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

## Billing

GET `/api/v1/teams/{teamId}/billing`

### Get a team's subscription

Read-only summary of a team's plan, subscription status, billing interval, add-on units, and renewal date. Requires the \`access\_billing\` permission. Checkout and plan changes are not exposed over the API.

[Scope `billing:read`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Read the subscription and billing status of your teams.") [MCP tool `getTeamBilling`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `getTeamBilling`

#### Parameters

`teamId` `string` Required in: path minLength 1 maxLength 255

#### Request

curl

```
curl "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/teams/{teamId}/billing" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The team's subscription. `application/json object`

`planId` `string` Required

`planName` `string` Required

`status` `string` Required nullable

`interval` `string` Required nullable

`addons` `object<string, number>` Required

`planExpiresAt` `string` Required nullable format: date-time

`cancelAtPeriodEnd` `boolean` Required

`needsPaymentAction` `boolean` Required

Example

```
{
  "planId" :  "string" ,
  "planName" :  "string" ,
  "status" :  "string" ,
  "interval" :  "string" ,
  "addons" :  {
    "key" :  0
  } ,
  "planExpiresAt" :  "2026-01-01T00:00:00.000Z" ,
  "cancelAtPeriodEnd" :  true ,
  "needsPaymentAction" :  true
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

## API keys

GET `/api/v1/api-keys`

### List API keys

Lists the caller's personal API keys, or a team's keys when \`teamId\` is given (which requires the \`manage\_api\_keys\` permission on that team). Revoked keys are never listed, and no response can ever contain a key's secret. Account-level: a team-scoped API key is refused with 403.

[Scope `api-keys:read`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "List the API keys on your account and when they were last used.") [MCP tool `listApiKeys`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `listApiKeys`

#### Parameters

`teamId` `string` Optional in: query minLength 1 maxLength 255

#### Request

curl

```
curl "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/api-keys" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The matching API keys. `application/json object[]`

`id` `string` Required

`name` `string` Required

`keyPrefix` `string` Required

`last4` `string` Required

`scopes` `string[]` Required

`teamId` `string` Required nullable

`createdAt` `string` Required format: date-time

`lastUsedAt` `string` Required nullable format: date-time

`expiresAt` `string` Required nullable format: date-time

Example

```
[
  {
    "id" :  "string" ,
    "name" :  "string" ,
    "keyPrefix" :  "string" ,
    "last4" :  "string" ,
    "scopes" :  [
      "string"
    ] ,
    "teamId" :  "string" ,
    "createdAt" :  "2026-01-01T00:00:00.000Z" ,
    "lastUsedAt" :  "2026-01-01T00:00:00.000Z" ,
    "expiresAt" :  "2026-01-01T00:00:00.000Z"
  }
]
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

POST `/api/v1/api-keys`

### Create an API key

Creates an API key for the caller, or for a team when \`teamId\` is given. The scopes requested must be a subset of the calling credential's own scopes. A key created with a \`teamId\` cannot hold a scope this API marks account-only; the refusal names the rejected scopes, so ask for a personal key instead when you need those. The \`secret\` in the response is returned exactly once and is not recoverable afterwards. Account-level: a team-scoped API key is refused with 403.

[Scope `api-keys:write`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Create and revoke API keys on your account.") [MCP tool `createApiKey`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `createApiKey`

#### Request body

`application/json`

`name` `string` Required minLength 1 maxLength 100

`scopes` `string[]` Required minItems 1 maxItems 10

enum: profile:read profile:write teams:read teams:write members:read members:write invites:write billing:read api-keys:read api-keys:write

`teamId` `string` Optional minLength 1 maxLength 255

`expiresInDays` `integer` Optional minimum 1 maximum 365

#### Request

curl

```
curl -X POST "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/api-keys" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "string",
  "scopes": [
    "profile:read"
  ],
  "teamId": "string",
  "expiresInDays": 1
}'
```

#### Response

201 The created key and its one-time secret. `application/json object`

`key` `object` Required

`key.id` `string` Required

`key.name` `string` Required

`key.keyPrefix` `string` Required

`key.last4` `string` Required

`key.scopes` `string[]` Required

`key.teamId` `string` Required nullable

`key.createdAt` `string` Required format: date-time

`key.lastUsedAt` `string` Required nullable format: date-time

`key.expiresAt` `string` Required nullable format: date-time

`secret` `string` Required

Example

```
{
  "key" :  {
    "id" :  "string" ,
    "name" :  "string" ,
    "keyPrefix" :  "string" ,
    "last4" :  "string" ,
    "scopes" :  [
      "string"
    ] ,
    "teamId" :  "string" ,
    "createdAt" :  "2026-01-01T00:00:00.000Z" ,
    "lastUsedAt" :  "2026-01-01T00:00:00.000Z" ,
    "expiresAt" :  "2026-01-01T00:00:00.000Z"
  } ,
  "secret" :  "string"
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

PATCH `/api/v1/api-keys/{keyId}`

### Update an API key's scopes

Replaces the scopes granted to an API key; the list is not merged with the key's current scopes, so send the full set you want it to end up with. The new scopes must be a subset of the calling credential's own scopes. The change takes effect immediately, including for the key making the call. Keys belonging to another account, and revoked keys, answer 404 so key ids cannot be probed. Account-level: a team-scoped API key is refused with 403.

[Scope `api-keys:write`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Create and revoke API keys on your account.") [MCP tool `updateApiKey`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `updateApiKey`

#### Parameters

`keyId` `string` Required in: path minLength 1 maxLength 255

#### Request body

`application/json`

`scopes` `string[]` Required minItems 1 maxItems 10

enum: profile:read profile:write teams:read teams:write members:read members:write invites:write billing:read api-keys:read api-keys:write

#### Request

curl

```
curl -X PATCH "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/api-keys/{keyId}" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "scopes": [
    "profile:read"
  ]
}'
```

#### Response

200 The updated key. `application/json object`

`id` `string` Required

`name` `string` Required

`keyPrefix` `string` Required

`last4` `string` Required

`scopes` `string[]` Required

`teamId` `string` Required nullable

`createdAt` `string` Required format: date-time

`lastUsedAt` `string` Required nullable format: date-time

`expiresAt` `string` Required nullable format: date-time

Example

```
{
  "id" :  "string" ,
  "name" :  "string" ,
  "keyPrefix" :  "string" ,
  "last4" :  "string" ,
  "scopes" :  [
    "string"
  ] ,
  "teamId" :  "string" ,
  "createdAt" :  "2026-01-01T00:00:00.000Z" ,
  "lastUsedAt" :  "2026-01-01T00:00:00.000Z" ,
  "expiresAt" :  "2026-01-01T00:00:00.000Z"
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

DELETE `/api/v1/api-keys/{keyId}`

### Revoke an API key

Revokes an API key immediately, including the key making the call. Keys belonging to another account answer 404 so key ids cannot be probed. Account-level: a team-scoped API key is refused with 403.

[Scope `api-keys:write`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/authentication.md "Create and revoke API keys on your account.") [MCP tool `revokeApiKey`](https://nextjs-saas-template.lubomirgeorgiev.com/docs/mcp.md) Operation `revokeApiKey`

#### Parameters

`keyId` `string` Required in: path minLength 1 maxLength 255

#### Request

curl

```
curl -X DELETE "https://nextjs-saas-template.lubomirgeorgiev.com/api/v1/api-keys/{keyId}" \
  -H "Authorization: Bearer $API_KEY"
```

#### Response

200 The key was revoked. `application/json object`

`success` `boolean` Required const: true

Example

```
{
  "success" :  true
}
```

Error responses

- 400

  The request body, query, or path failed validation.

- 401

  The credential is missing, malformed, expired, or revoked.

- 403

  The credential lacks the required scope or the caller lacks the team permission.

- 404

  The addressed resource does not exist or is not visible to this credential.

- 429

  Rate limit exceeded; retry after the number of seconds in \`retry-after\`. The \`RateLimit-\*\` headers describe the exhausted bucket.

No endpoint matches that filter.
