NoteBugsDocs

API reference

Profile

Your own profile, password, avatar and token.

This prefix requires only being authenticated: even a VIEWER, who does not write on the board, changes their own password and avatar.

GET/api/profile
Role: Viewer

Your own profile, with your workspaces and your role in each.

Request

curl -s http://localhost:3000/api/profile \
  -H "Authorization: Bearer $TOKEN"

Response200

{
  "id": "cmt94cjx5000vql01imegem2r",
  "name": "Ana",
  "email": "[email protected]",
  "role": "ADMIN",
  "avatarUrl": null,
  "jobTitle": "Product Owner",
  "timezone": "America/Sao_Paulo",
  "notifyBackupReady": true,
  "hasApiToken": true,
  "apiTokenCreatedAt": "2026-08-25T20:37:29.998Z",
  "apiTokenLast4": "mGQ",
  "passwordPending": false,
  "lastLoginAt": "2026-08-27T19:50:42.947Z",
  "createdAt": "2026-08-25T20:29:57.593Z",
  "tenants": [
    {
      "id": "cmsp4djx60002p801o7ybpkv7",
      "name": "Pessoal",
      "color": "amber",
      "role": "ADMIN",
      "membership": null
    }
  ]
}

Error responses

CodeWhen it happens
401No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.

There is no /api/profile/[id]: nobody edits someone else's profile.

PATCH/api/profile
Role: Viewer

Edits your own name, e-mail, job title, timezone and the backup notification preference.

Request body

FieldTypeDescription
namestring
emailstring
jobTitlestring | nullnull clears the job title; absent does not touch it.
timezonestringDISPLAY timezone. Empty is meaningful: “use the default”, which is America/Sao_Paulo.When absent: America/Sao_Paulo
notifyBackupReadybooleanWhether to be told when a backup is ready.

Request

curl -s -X PATCH http://localhost:3000/api/profile \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "jobTitle": "Product Owner", "timezone": "America/Sao_Paulo" }'

Response200

{
  "id": "cmt94cjx5000vql01imegem2r",
  "name": "Ana",
  "email": "[email protected]",
  "role": "ADMIN",
  "avatarUrl": null,
  "jobTitle": "Product Owner",
  "timezone": "America/Sao_Paulo",
  "notifyBackupReady": true,
  "hasApiToken": true,
  "apiTokenCreatedAt": "2026-08-25T20:37:29.998Z",
  "apiTokenLast4": "mGQ",
  "passwordPending": false,
  "lastLoginAt": "2026-08-27T19:50:42.947Z",
  "createdAt": "2026-08-25T20:29:57.593Z",
  "tenants": [
    {
      "id": "cmsp4djx60002p801o7ybpkv7",
      "name": "Pessoal",
      "color": "amber",
      "role": "ADMIN",
      "membership": null
    }
  ]
}

Error responses

CodeWhen it happens
401No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.
409Another account already uses that e-mail.
422The body did not pass the schema. The details field carries zod's fieldErrors and formErrors, field by field.

No role and no tenants: nobody promotes or invites themselves. That is PATCH /api/users/[id], which only an admin reaches.

PATCH/api/profile/password
Role: Viewer

Changes your own password, requiring the current one.

The current password is required even on an already authenticated session.

Request body

FieldTypeDescription
currentPasswordrequiredstring
newPasswordrequiredstring

Request

curl -s -X PATCH http://localhost:3000/api/profile/password \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "currentPassword": "a senha de agora",
    "newPassword": "uma senha nova e longa"
  }'

Response200

{ "ok": true }

Error responses

CodeWhen it happens
401The current password provided does not match.
422The body did not pass the schema. The details field carries zod's fieldErrors and formErrors, field by field.

Changing the password drops the OTHER sessions; this tab's stays valid.

POST/api/profile/avatar
Role: Viewermultipart/form-data

Uploads the profile picture.

Images only, identified by the file's magic bytes. The container's veto (uploadMode: NONE) still holds above the screen's choice.

Request body

FieldTypeDescription
filerequiredarquivo

Request

curl -s -X POST http://localhost:3000/api/profile/avatar \
  -H "Authorization: Bearer $TOKEN" \
  -F "[email protected]"

Response200

{
  "id": "cmt94cjx5000vql01imegem2r",
  "name": "Ana",
  "email": "[email protected]",
  "role": "ADMIN",
  "avatarUrl": "/api/files/18ab694d-48ed-4b56-bd2b-3a324fec55de.png",
  "jobTitle": "Product Owner",
  "timezone": "America/Sao_Paulo",
  "notifyBackupReady": true,
  "hasApiToken": true,
  "apiTokenCreatedAt": "2026-08-25T20:37:29.998Z",
  "apiTokenLast4": "mGQ",
  "passwordPending": false,
  "lastLoginAt": "2026-08-27T19:50:42.947Z",
  "createdAt": "2026-08-25T20:29:57.593Z",
  "tenants": [
    {
      "id": "cmsp4djx60002p801o7ybpkv7",
      "name": "Pessoal",
      "color": "amber",
      "role": "ADMIN",
      "membership": null
    }
  ]
}

Error responses

CodeWhen it happens
401No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.
415The format is not accepted. It is identified by the magic bytes, not by the file name extension.
413The file is over the maximum size per attachment.

The avatar has no attachment row: it is resolved through the account's avatarName, and /api/files/[name] knows to look in both places.

DELETE/api/profile/avatar
Role: Viewer

Removes the profile picture.

Request

curl -s -X DELETE http://localhost:3000/api/profile/avatar \
  -H "Authorization: Bearer $TOKEN"

Response200

{
  "id": "cmt94cjx5000vql01imegem2r",
  "name": "Ana",
  "email": "[email protected]",
  "role": "ADMIN",
  "avatarUrl": null,
  "jobTitle": "Product Owner",
  "timezone": "America/Sao_Paulo",
  "notifyBackupReady": true,
  "hasApiToken": true,
  "apiTokenCreatedAt": "2026-08-25T20:37:29.998Z",
  "apiTokenLast4": "mGQ",
  "passwordPending": false,
  "lastLoginAt": "2026-08-27T19:50:42.947Z",
  "createdAt": "2026-08-25T20:29:57.593Z",
  "tenants": [
    {
      "id": "cmsp4djx60002p801o7ybpkv7",
      "name": "Pessoal",
      "color": "amber",
      "role": "ADMIN",
      "membership": null
    }
  ]
}

Error responses

CodeWhen it happens
401No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.
POST/api/profile/token
Role: Viewer

Generates the account's API token. The plain value comes out ONCE.

There is one token per person: generating again revokes the previous one, so revoking is a single action, with no token management screen.

Request

curl -s -X POST http://localhost:3000/api/profile/token \
  -b cookies.txt

Response200

{
  "token": "eumjKz6l6Erh9_gIYFG8-6ONNGcbST88LcwnbvswmGQ",
  "user": {
    "id": "cmt94cjx5000vql01imegem2r",
    "name": "Ana",
    "email": "[email protected]",
    "role": "ADMIN",
    "avatarUrl": null,
    "jobTitle": "Product Owner",
    "timezone": "America/Sao_Paulo",
    "notifyBackupReady": true,
    "hasApiToken": true,
    "apiTokenCreatedAt": "2026-08-25T20:37:29.998Z",
    "apiTokenLast4": "mGQ",
    "passwordPending": false,
    "lastLoginAt": "2026-08-27T19:50:42.947Z",
    "createdAt": "2026-08-25T20:29:57.593Z",
    "tenants": [
      {
        "id": "cmsp4djx60002p801o7ybpkv7",
        "name": "Pessoal",
        "color": "amber",
        "role": "ADMIN",
        "membership": null
      }
    ]
  }
}

Error responses

CodeWhen it happens
401No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.

Lost it, make another: there is no way to recover the value. What stays on the row, besides the sha256, are the last four characters, so the screen can say which token your script carries.

DELETE/api/profile/token
Role: Viewer

Revokes the account's API token.

Request

curl -s -X DELETE http://localhost:3000/api/profile/token \
  -b cookies.txt

Response200

{
  "id": "cmt94cjx5000vql01imegem2r",
  "name": "Ana",
  "email": "[email protected]",
  "role": "ADMIN",
  "avatarUrl": null,
  "jobTitle": "Product Owner",
  "timezone": "America/Sao_Paulo",
  "notifyBackupReady": true,
  "hasApiToken": false,
  "apiTokenCreatedAt": "2026-08-25T20:37:29.998Z",
  "apiTokenLast4": "mGQ",
  "passwordPending": false,
  "lastLoginAt": "2026-08-27T19:50:42.947Z",
  "createdAt": "2026-08-25T20:29:57.593Z",
  "tenants": [
    {
      "id": "cmsp4djx60002p801o7ybpkv7",
      "name": "Pessoal",
      "color": "amber",
      "role": "ADMIN",
      "membership": null
    }
  ]
}

Error responses

CodeWhen it happens
401No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.

Idempotent: whoever has no token gets no error.