Appearance
API v1 — Referência de integração
Referência dos endpoints da API v1, para quem vai consumir a API (dev ou LLM). Cada funcionalidade tem sua própria página:
llm.md— guia auto-contido para LLMs e agentes: contrato completo, entrada/saída de cada endpoint, tipos TypeScript, cliente pronto, receitas de integração e regras a seguir. Comece por aqui se for uma LLM.auth/— registro, login, logout, refresh, recuperação de senha e verificação de e-mail.organizations/— CRUD de organizações.users/— CRUD de usuários dentro de uma organização.clients/— CRUD de clientes dentro de uma organização.
Base URL
https://api.fastgivr.com.br. Todos os caminhos abaixo são relativos a /v1 (ex.: POST /v1/auth/login).
Autenticação
Token Bearer (JWT) via header Authorization: Bearer <access_token>. O access_token é obtido em POST /v1/auth/register ou POST /v1/auth/login.
Rotas marcadas como 🔒 Autenticado exigem esse header. As demais são públicas.
Formato de resposta (envelope padrão)
Sucesso:
json
{
"code": 200,
"success": true,
"<chave>": { "...": "..." },
"message": "Mensagem opcional de sucesso"
}A <chave> varia por endpoint (user, users, organization, organizations, data) — está indicada em cada endpoint documentado abaixo.
Erro:
json
{
"code": 422,
"success": false,
"data": { "campo": ["mensagem de validação"] },
"message": "Dados de entrada inválidos."
}data traz os detalhes do erro (ex.: erros de validação por campo) quando existirem, ou null.
Contexto de organização (importante para users/ e clients/)
Um usuário pode pertencer a várias organizações. Os endpoints em organizations/ sempre operam sobre uma organização explícita ({id} na URL). Já os endpoints em users/ e clients/ operam sobre a organização em contexto, resolvida assim:
- Se o header
organizationouX-Organization-Idfor enviado com o uuid de uma organização à qual o usuário pertence, essa é a organização usada. - Caso contrário, cai para a organização de maior
identre as quais o usuário pertence (a mais recente). - Se o usuário não pertencer a nenhuma organização, a API responde com erro (organização não encontrada).
Recomendação para o front-end: sempre que o usuário estiver operando dentro de uma organização específica (ex.: um seletor de organização na UI), envie o header X-Organization-Id: <uuid-da-organizacao> em toda chamada a users/* e clients/*. O uuid de cada organização vem no campo uuid do objeto retornado por organizations/*.
Status de Organização
Valores possíveis do campo status: ACTIVE, INACTIVE, SUSPENDED, DISABLED, DISQUALIFIED, SOFT_DELETED, DELETED. Organizações são criadas com status INACTIVE por padrão.
Tipos genéricos (TypeScript)
Use estes tipos como base para qualquer chamada — todos os endpoints desta API respeitam o mesmo envelope:
ts
type ApiSuccess<T, Key extends string = "data"> = {
code: number;
success: true;
message?: string;
} & { [K in Key]: T };
type ApiError = {
code?: number;
success: false;
data: Record<string, string[]> | string | null;
message: string;
};
type ApiResult<T, Key extends string = "data"> = ApiSuccess<T, Key> | ApiError;Cliente mínimo (fetch)
Exemplo de wrapper que já resolve base URL, Authorization e o header de organização — use como referência para gerar o client do front-end:
ts
const BASE_URL = "https://api.fastgivr.com.br/v1";
type ApiOptions = {
token?: string; // access_token retornado por /auth/login ou /auth/register
organizationUuid?: string; // uuid da organização em contexto (rotas de /users)
body?: unknown;
};
async function apiFetch<T = unknown>(
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE",
path: string, // ex.: '/auth/login', '/organizations', '/users/5'
{ token, organizationUuid, body }: ApiOptions = {},
): Promise<T> {
const headers: Record<string, string> = {
"Content-Type": "application/json",
};
if (token) headers["Authorization"] = `Bearer ${token}`;
if (organizationUuid) headers["X-Organization-Id"] = organizationUuid;
const res = await fetch(`${BASE_URL}${path}`, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
});
const json = await res.json();
if (!res.ok || json.success === false) {
throw new Error(json.message ?? "Erro desconhecido na API");
}
return json;
}
// Exemplos de uso:
// await apiFetch('POST', '/auth/login', { body: { email, password } });
// await apiFetch('GET', '/users', { token, organizationUuid });Fluxos recomendados
Cadastro + primeira organização:
POST /auth/register→ guardaaccess_token.POST /organizations(com o token) → cria a primeira organização do usuário; guarde ouuidretornado — é o que vai no headerX-Organization-Iddaqui em diante.POST /auth/send-verification-code/POST /auth/verify-email→ fluxo de verificação de e-mail (opcional, não bloqueia o uso da API).
Login e uso normal:
POST /auth/login→ guardaaccess_token.GET /auth/me→ lista as organizações do usuário (organizations[].uuid); deixe o usuário escolher uma no seletor de organização da UI, se houver mais de uma.- Toda chamada a
/users/*incluiAuthorization: Bearer <token>eX-Organization-Id: <uuid escolhido>.
Sessão expirada / token perto de expirar:
- Use
expires_in(segundos) da resposta de login/registro para agendarPOST /auth/refreshantes de expirar, substituindo oaccess_tokenguardado. - Se qualquer chamada 🔒 retornar 401, o token está inválido/expirado — a resposta vem como
{"success": false, ...}; redirecione para o login.