NoteBugsDocs

Referência da API

Perfil

O próprio perfil, a própria senha, o próprio avatar e o próprio token.

Este prefixo exige apenas estar autenticado: mesmo um VIEWER, que não escreve no quadro, troca a própria senha e o próprio avatar.

GET/api/profile
Papel: Leitor

O próprio perfil, com os espaços de trabalho e o papel em cada um.

Requisição

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

Resposta200

{
  "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
    }
  ]
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.

Não existe /api/profile/[id]: ninguém edita o perfil de outra pessoa.

PATCH/api/profile
Papel: Leitor

Edita o próprio nome, e-mail, cargo, fuso e a preferência de aviso de backup.

Corpo da requisição

CampoTipoDescrição
namestring
emailstring
jobTitlestring | nullnull limpa o cargo; ausente não mexe.
timezonestringFuso de EXIBIÇÃO. Vazio é significativo: “use o padrão”, que é America/Sao_Paulo.Ausente: America/Sao_Paulo
notifyBackupReadybooleanAvisar quando um backup ficar pronto.

Requisição

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" }'

Resposta200

{
  "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
    }
  ]
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
409Outra conta já usa esse e-mail.
422O corpo não passou pelo schema. O campo details traz fieldErrors e formErrors do zod, campo a campo.

Sem role e sem tenants: ninguém se promove nem se convida. Isso é PATCH /api/users/[id], que só um administrador alcança.

PATCH/api/profile/password
Papel: Leitor

Troca a própria senha, exigindo a atual.

A senha atual é exigida mesmo com a sessão já autenticada.

Corpo da requisição

CampoTipoDescrição
currentPasswordobrigatóriostring
newPasswordobrigatóriostring

Requisição

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"
  }'

Resposta200

{ "ok": true }

Respostas de erro

CódigoQuando acontece
401A senha atual informada não confere.
422O corpo não passou pelo schema. O campo details traz fieldErrors e formErrors do zod, campo a campo.

Trocar a senha derruba as OUTRAS sessões; a desta aba continua valendo.

POST/api/profile/avatar
Papel: Leitormultipart/form-data

Envia a foto do perfil.

Só imagem, identificada pelos magic bytes do arquivo. O veto do container (uploadMode: NONE) continua valendo por cima da escolha da tela.

Corpo da requisição

CampoTipoDescrição
fileobrigatórioarquivo

Requisição

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

Resposta200

{
  "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
    }
  ]
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
415O formato não é aceito. Ele é identificado pelos magic bytes, e não pela extensão do nome.
413O arquivo passa do tamanho máximo por anexo.

O avatar não tem linha de anexo: ele é resolvido pelo avatarName da conta, e /api/files/[name] sabe procurar nos dois lugares.

DELETE/api/profile/avatar
Papel: Leitor

Remove a foto do perfil.

Requisição

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

Resposta200

{
  "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
    }
  ]
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
POST/api/profile/token
Papel: Leitor

Gera o token de API da conta. O valor em claro sai UMA vez.

Existe um token por pessoa: gerar de novo revoga o anterior, então revogar é uma ação só, sem tela de gestão de tokens.

Requisição

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

Resposta200

{
  "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
      }
    ]
  }
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.

Perdeu, gera outro: não há como recuperar o valor. O que fica na linha, além do sha256, são os quatro últimos caracteres, para a tela poder dizer qual token o script carrega.

DELETE/api/profile/token
Papel: Leitor

Revoga o token de API da conta.

Requisição

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

Resposta200

{
  "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
    }
  ]
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.

Idempotente: quem não tem token não recebe erro.