/v1/signup
Autocadastro: criar a clínica do usuário autenticado (teste grátis do plano)
Primeiro o dono cria a conta (e-mail e senha) no provedor de identidade da plataforma; depois, com o token dessa conta, chama esta rota. Nome e e-mail do dono vêm do token — nunca do corpo.
Cria, numa chamada só: a clínica (status ONBOARDING), o vínculo do dono como Administrador e a assinatura do plano escolhido em teste grátis de 7 dias (trialEndsAt). Durante o teste nada é cobrado; ao fim, sem ativação, o painel fica em somente leitura (402 trial_expired nas escritas).
Idempotente: repetir a chamada (mesmo usuário) devolve 200 com o mesmo clinicId e created: false, sem duplicar nada; a primeira criação devolve 201. Duas chamadas simultâneas criam uma clínica só. Cada usuário cria no máximo uma clínica por esta rota.
Depois do cadastro, GET /v1/me já responde com a clínica nova (envie X-Clinic-Id se a pessoa também tiver acesso a outras clínicas).
Erros: 503 signup_disabled (cadastro ainda não aberto no ambiente), 403 signup_not_allowed (token de serviço ou equipe da plataforma), 400 (campo-isca preenchido), 409 signup_conflict (estado inconsistente — fale com o suporte), 422 unknown_plan / plan_requires_sales / invalid_cnpj / validation_error.
clinic.createdAutenticação
Envie o token de acesso do usuário no cabeçalho Authorization. Integrações servidor a servidor usam o token de serviço com X-Clinic-Id e X-Agent-Key. Como autenticar
Authorization: Bearer <TOKEN>Parâmetros
Corpo da requisição
application/json · obrigatório
clinicobjectObrigatórionamestringObrigatórioclinic.nameEntre 2 e 128 caracteres
cnpjstringOpcionalclinic.cnpjOpcional. Os dígitos verificadores são conferidos (422 invalid_cnpj). · Padrão (regex):
^\d{2}\.?\d{3}\.?\d{3}/?\d{4}-?\d{2}$phonestringObrigatórioclinic.phoneTelefone de contato da clínica. · Entre 8 e 32 caracteres · Padrão (regex):
^[0-9+()\s.-]+$emailstring (e-mail)Obrigatórioclinic.emailE-mail de contato da clínica (pode ser diferente do e-mail de login). · Até 160 caracteres
zipstringOpcionalclinic.zipPadrão (regex):
^\d{5}-?\d{3}$streetstringObrigatórioclinic.streetEndereço (rua, número, bairro). · Entre 5 e 160 caracteres
citystringOpcionalclinic.cityAté 80 caracteres
statestringOpcionalclinic.statePadrão (regex):
^[A-Za-z]{2}$specialtystringObrigatórioclinic.specialtyÁrea de atuação principal. · Entre 2 e 64 caracteres
teamSizestringObrigatórioclinic.teamSizeTamanho da equipe: solo (só eu), 2-5, 6-20, 20+. · Valores:
solo,2-5,6-20,20+ownerobjectObrigatóriophonestringObrigatórioowner.phoneWhatsApp do dono da conta. · Entre 8 e 32 caracteres · Padrão (regex):
^[0-9+()\s.-]+$jobTitlestringOpcionalowner.jobTitleCargo ou função. · Até 80 caracteres
marketingOptInbooleanObrigatórioowner.marketingOptInAceita receber novidades e dicas por e-mail/WhatsApp.
planobjectObrigatórioidstringObrigatórioplan.idPlano com preço publicado (GET /v1/billing/plans com selfSignup = true). Sob consulta → 422 plan_requires_sales. · Padrão (regex):
^[a-z0-9-]{1,32}$cyclestringObrigatórioplan.cycleCiclo de cobrança escolhido no site (vale depois do teste). · Valores:
mensal,anualconsentobjectObrigatórioacceptedbooleanObrigatórioconsent.acceptedAceite dos Termos de Uso e da Política de Privacidade (obrigatório). · Valores:
truetermsVersionstringObrigatórioconsent.termsVersionVersão dos Termos de Uso exibida no aceite. · Entre 1 e 32 caracteres · Padrão (regex):
^[A-Za-z0-9._-]+$privacyVersionstringObrigatórioconsent.privacyVersionVersão da Política de Privacidade exibida no aceite. · Entre 1 e 32 caracteres · Padrão (regex):
^[A-Za-z0-9._-]+$websitestringOpcionalCampo-isca anti-robô: o formulário deve mantê-lo oculto e vazio. Preenchido → 400. · Até 200 caracteres
Exemplo de requisição
Gerado do contrato. Troque os marcadores entre < > pelos seus valores.
const res = await fetch("https://myclinc.leadpoint.com.br/v1/signup", { method: "POST", headers: { Authorization: "Bearer <TOKEN>", "X-Agent-Key": "<agent_key>", "Content-Type": "application/json", }, body: JSON.stringify({ "clinic": { "name": "Clínica Exemplo", "phone": "(16) 99999-0000", "email": "contato@exemplo.com", "street": "<street>", "specialty": "Fisioterapia", "teamSize": "solo" }, "owner": { "phone": "(16) 99999-0000", "marketingOptIn": true, "jobTitle": "Fisioterapeuta" }, "plan": { "id": "profissional", "cycle": "mensal" }, "consent": { "accepted": true, "termsVersion": "2026-09", "privacyVersion": "2026-09" }, "website": "<website>" }),})if (!res.ok) { const { error } = await res.json() throw new Error(`${error.code}: ${error.message} (${error.requestId})`)}const { data } = await res.json()Resposta
{ "data": { "clinicId": "clin_3f9a1c2b7d4e5f60a1b2", "planId": "profissional", "cycle": "mensal", "trialEndsAt": "2026-09-18T14:00:00.000Z", "created": true }, "meta": { "webhooks": [ { "event": "appointment.cancelled", "status": "sent" } ] }}{ "data": { "clinicId": "clin_3f9a1c2b7d4e5f60a1b2", "planId": "profissional", "cycle": "mensal", "trialEndsAt": "2026-09-18T14:00:00.000Z", "created": true }, "meta": { "webhooks": [ { "event": "appointment.cancelled", "status": "sent" } ] }}Exemplo gerado do esquema da resposta; valores entre < > são ilustrativos.
Códigos de erro
Corpo no formato padrão { error: { code, message, requestId } }. Veja todos os códigos.
Bad Request — Requisição malformada (JSON inválido, cursor inválido ou clínica ativa não informada).
Unauthorized — Token ausente, inválido ou expirado.
Forbidden — Autenticado, mas sem permissão (perfil ou clínica).
Conflict — Conflito de estado (duplicidade, transição inválida, conflito de agenda).
Unprocessable Entity — Dados semanticamente inválidos (erros por campo em details).
Too Many Requests — Limite de requisições excedido (veja Retry-After).
Internal Server Error — Erro interno (sem detalhes expostos).
Service Unavailable — Banco de dados indisponível ou não configurado.
Limites
Esta operação tem limite próprio: 5 requisições / 3600 s por IP. Sobre limites