API: criar company (POST) — guia para o frontend
Canónico: guias/post-company.md · apis/05-companies.md · catálogo.
Documento de referência para integração do cadastro de empresa (company) na API CentralCRM.
Dois sistemas: o login (
POST /api/v1/auth/login) usa outro banco (user_profiles) e emite JWT semtenantId. Para criar/listar companies neste backend é necessário JWT comsubetenantId(ver secção Autenticação abaixo).
Endpoint
| Item | Valor |
|---|---|
| Método | POST |
| URL | {BASE_URL}/api/v1/companies |
| Exemplo | https://api.seudominio.com/api/v1/companies |
Versão da API na URL: v1.
Autenticação (obrigatória)
Todas as rotas de /api/v1/companies exigem JWT no header:
Authorization: Bearer <access_token>
O token deve ser assinado com o mesmo JWT_SECRET configurado no backend e conter no payload (claims):
| Claim | Tipo | Obrigatório | Descrição |
|---|---|---|---|
sub | string | Sim | Identificador do usuário (ex.: UUID do usuário no sistema). |
tenantId | string (UUID) | Sim | Tenant ao qual a company será vinculada. O backend não usa mais o header X-Tenant-Id para essa rota — o isolamento multi-tenant vem deste claim. |
Se o token estiver ausente, inválido ou expirado, a API responde 401 Unauthorized.
Corpo da requisição (Content-Type: application/json)
Envie um objeto JSON com os campos abaixo.
Campos
| Campo (JSON) | Obrigatório | Tipo | Limite / regras | Descrição |
|---|---|---|---|---|
razaoSocial | Sim | string | máx. 255 caracteres, não vazio | Razão social da empresa. |
nomeFantasia | Não | string | máx. 255 | Nome fantasia. |
cnpj | Não | string | máx. 18 | CNPJ (formato livre no envio; unicidade é por tenant no banco). |
email | Não | string | e-mail válido, máx. 255 | E-mail de contato. |
telefone | Não | string | máx. 20 | Telefone. |
status | Não | string (enum) | Ver tabela abaixo | Situação da company. |
metadata | Não | object | JSON objeto | Metadados extras (chave/valor livre para o produto). |
Valores aceitos para status
Se omitido, o backend grava como ativo.
| Valor enviado | Significado |
|---|---|
ativo | Company ativa (padrão). |
inativo | Company inativa. |
suspenso | Company suspensa. |
Comportamento de campos opcionais omitidos
nomeFantasia,cnpj,email,telefone: armazenados comonullse não enviados.status: assumeativo.metadata: assume{}(objeto vazio).
Validação (erros comuns)
- Propriedades não listadas no contrato podem ser rejeitadas (
400) se o backend estiver com validação estrita (whitelist). - Corpo inválido (tipos errados,
razaoSocialvazio, e-mail inválido, etc.) →400 Bad Requestcom mensagem de validação.
Resposta de sucesso
| HTTP | Significado |
|---|---|
| 201 Created | Company criada. |
Corpo JSON de exemplo (campos retornados):
| Campo | Tipo | Descrição |
|---|---|---|
id | string (UUID) | ID da company criada. |
tenantId | string (UUID) | Igual ao tenantId do JWT. |
razaoSocial | string | |
nomeFantasia | string | null | |
cnpj | string | null | |
email | string | null | |
telefone | string | null | |
status | string | Ex.: "ativo". |
metadata | object | |
createdAt | string | Data/hora ISO 8601 (UTC). |
updatedAt | string | Data/hora ISO 8601 (UTC). |
Erros relevantes
| HTTP | Quando |
|---|---|
| 400 | JSON inválido ou falha nas regras de validação (campos obrigatórios, formatos). |
| 401 | Sem Authorization, token inválido ou expirado. |
| 409 Conflict | Violação de unicidade no banco (ex.: mesmo CNPJ já cadastrado para o mesmo tenant). |
Exemplo mínimo (fetch)
const baseUrl = 'https://api.seudominio.com';
const accessToken = '...'; // JWT com sub e tenantId
const res = await fetch(`${baseUrl}/api/v1/companies`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({
razaoSocial: 'Minha Empresa LTDA',
}),
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error(err.message ?? res.statusText);
}
const company = await res.json();
// company.id, company.tenantId, ...
Exemplo completo (todos os campos opcionais)
{
"razaoSocial": "ACME Serviços LTDA",
"nomeFantasia": "ACME",
"cnpj": "12345678000199",
"email": "contato@acme.com.br",
"telefone": "11987654321",
"status": "ativo",
"metadata": {
"origemCadastro": "web",
"codigoInterno": 12345
}
}
Tipagem TypeScript (referência)
type CompanyStatus = 'ativo' | 'inativo' | 'suspenso';
interface CreateCompanyRequest {
razaoSocial: string;
nomeFantasia?: string;
cnpj?: string;
email?: string;
telefone?: string;
status?: CompanyStatus;
metadata?: Record<string, unknown>;
}
interface CompanyResponse {
id: string;
tenantId: string;
razaoSocial: string;
nomeFantasia: string | null;
cnpj: string | null;
email: string | null;
telefone: string | null;
status: string;
metadata: Record<string, unknown>;
createdAt: string;
updatedAt: string;
}
Gerado a partir do contrato atual do backend (CreateCompanyRequestDto, CompanyResponseDto, guard JWT).