API · v1

Receba pedidos de visita do seu site

Se você já tem um site e não quer trocar o formulário dele, pode mandar os pedidos direto pro StudioOS. Eles entram na sua conta como qualquer outra solicitação — com rodízio de vendedor, notificação e agenda.

Introdução

A API tem duas rotas e nenhuma etapa de aprovação. Você gera uma chave dentro do app, envia um POST com os dados do cliente e o pedido aparece no painel na hora.

Todas as URLs começam em https://pqceyzucuydbjnjxrduh.supabase.co/functions/v1. As respostas são sempre JSON, e os textos de erro vêm em português — dá pra mostrar ao visitante sem traduzir.

Obter uma chave

No StudioOS, entre em Configurações → Integrações e procure a seção API para o seu site. Dê um nome à chave (use o lugar onde ela vai rodar, tipo "site institucional") e clique em Gerar chave.

A chave aparece uma única vez. Guardamos só um resumo criptográfico dela, então nem nós conseguimos mostrá-la de novo — se perder, revogue e gere outra. Só o administrador da empresa vê essa seção.

Cada chave pertence a uma empresa. É por isso que você não precisa informar qual empresa é: nós descobrimos pela chave.

Abrir Configurações → Integrações →

Autenticação

Mande a chave no cabeçalho x-api-key. Nenhum outro cabeçalho de autenticação é necessário.

http
x-api-key: sk_live_…
Content-Type: application/json

Se preferir, o formato Bearer sk_live_… também é aceito no mesmo cabeçalho — os dois valem a mesma coisa.

Trate a chave como senha. Quem a tiver pode criar solicitações em nome da sua empresa. Ela deve ficar no servidor do seu site, nunca no JavaScript que o visitante baixa — no navegador, qualquer pessoa lê a chave em dois cliques.

Criar solicitação de visita

Cria o pedido na sua conta e devolve o identificador dele.

POSThttps://pqceyzucuydbjnjxrduh.supabase.co/functions/v1/save-visit-request
CampoTipoObrigatórioObservação
nomestringsimMínimo 2 caracteres.
emailstringsimPrecisa ter formato de e-mail.
telefonestringsimMínimo 10 caracteres. Pode vir com máscara: (47) 99999-9999.
cidadestringsimUsada no rodízio: quem atende aquela cidade recebe o lead.
data_agendadastringsimFormato AAAA-MM-DD. Outro formato é recusado pelo banco (erro 500).
horario_agendadostringsimTexto livre, como "14:00" ou "Manhã".
enderecostringnãoEndereço da visita.
complementostringnãoApartamento, bloco, referência.
mensagemstringnãoO que o cliente escreveu.
atribuicaoobjetonãoOrigem do clique. Só estas chaves são aceitas: gclid, gbraid, wbraid, utm_source, utm_medium, utm_campaign, utm_term, utm_content, landing_page, captured_at. Cada valor é cortado em 300 caracteres.

Enviar organization_slug junto não faz nada quando há chave: a empresa vem sempre da chave. É de propósito — sem isso, bastaria mandar o identificador de outra empresa para plantar pedidos na conta dela.

Respostas

json
# 200 — criada
{"success": true, "id": "3fa912ff-3575-4f49-b51b-56fd74b65a8f"}

# 400 — campo inválido (a mensagem lista todos de uma vez)
{"success": false, "error": "Email inválido, Data inválida"}

# 401 — chave errada, revogada ou inexistente
{"success": false, "error": "api_key_invalida",
 "message": "Chave de API inválida ou revogada."}

# 429 — passou de 60 por minuto (o header Retry-After diz quanto esperar)
{"success": false, "error": "Muitas requisições. Tente novamente em 1 minuto."}

Dois pedidos com o mesmo telefone, com o primeiro ainda em aberto, vão para o mesmo vendedor — evita que o cliente seja atendido duas vezes por pessoas diferentes.

Dados públicos da empresa

Útil se você quer montar o formulário com o nome, o logo e a cor da empresa. Não precisa de chave e devolve só dados de vitrine.

POSThttps://pqceyzucuydbjnjxrduh.supabase.co/functions/v1/captacao-org
bash
curl -X POST https://pqceyzucuydbjnjxrduh.supabase.co/functions/v1/captacao-org \
  -H "Content-Type: application/json" \
  -d '{"slug": "sua-empresa"}'

# 200
# {"found":true,"org":{"name":"Sua Empresa","logo_url":"https://…",
#  "whatsapp":"5547999990000","primary_color":"#8b6f3f"}}

Identificador inexistente devolve 404 com {"found": false}. Limite de 60 chamadas por minuto por IP.

Exemplos prontos

Linha de comando

Troque SUA_CHAVE_AQUI e rode. É o teste mais rápido para saber se a chave está válida.

curl
curl -X POST https://pqceyzucuydbjnjxrduh.supabase.co/functions/v1/save-visit-request \
  -H "Content-Type: application/json" \
  -H "x-api-key: SUA_CHAVE_AQUI" \
  -d '{
    "nome": "Maria Souza",
    "email": "maria@exemplo.com.br",
    "telefone": "(47) 99999-0000",
    "cidade": "Balneário Camboriú",
    "data_agendada": "2026-08-05",
    "horario_agendado": "14:00",
    "mensagem": "Quero orçamento de blackout para 3 quartos."
  }'

JavaScript (no servidor)

javascript
async function enviarSolicitacao(dados) {
  const resposta = await fetch(
    'https://pqceyzucuydbjnjxrduh.supabase.co/functions/v1/save-visit-request',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-api-key': SUA_CHAVE, // nunca no código do navegador — veja o aviso abaixo
      },
      body: JSON.stringify(dados),
    },
  );

  const corpo = await resposta.json();
  if (!resposta.ok) {
    // 400 = campo inválido · 401 = chave · 429 = limite
    throw new Error(corpo.error ?? 'Falha ao enviar');
  }
  return corpo.id;
}

Formulário HTML

O formulário fala com o seu servidor, que guarda a chave e repassa para nós. Assim a chave nunca chega ao navegador do visitante.

html
<form id="visita">
  <input name="nome" placeholder="Seu nome" required />
  <input name="email" type="email" placeholder="Seu e-mail" required />
  <input name="telefone" placeholder="(47) 99999-0000" required />
  <input name="cidade" placeholder="Sua cidade" required />
  <input name="data_agendada" type="date" required />
  <input name="horario_agendado" placeholder="14:00" required />
  <textarea name="mensagem" placeholder="O que você precisa?"></textarea>
  <button type="submit">Agendar visita</button>
</form>

<script>
  document.getElementById('visita').addEventListener('submit', async (e) => {
    e.preventDefault();
    const dados = Object.fromEntries(new FormData(e.target));

    // Este fetch aponta pro SEU servidor, que guarda a chave e repassa
    // pra API do StudioOS. Ver "Erros comuns" sobre por que não chamar direto.
    const r = await fetch('/api/agendar-visita', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(dados),
    });

    alert(r.ok ? 'Recebemos seu pedido!' : 'Não conseguimos enviar. Tente de novo.');
  });
</script>

Erros comuns

401 · api_key_invalida

A chave não existe, foi revogada ou veio com espaço colado no copiar. Repare que não caímos em silêncio no modo anônimo: se a chave está errada, você o erro — em silêncio, o pedido cairia na conta errada por meses sem ninguém notar.

400 · campo inválido

A mensagem lista todos os problemas de uma vez ("Email inválido, Data inválida"). O caso mais frequente é data_agendada fora do formato AAAA-MM-DD.

429 · muitas requisições

Passou de 60 chamadas por minuto naquela chave. O cabeçalho Retry-After diz em quantos segundos tentar de novo. Se seu site tem pico legítimo acima disso, fale com a gente antes de gerar várias chaves para contornar.

500 · erro ao salvar

Quase sempre é data_agendada num formato que o banco recusa. Mande AAAA-MM-DD.

O pedido não aparece no painel

Confira em Configurações → Integrações se a chave mostra um "último uso" recente. "Nunca usada" significa que a chamada não chegou até nós — o problema está antes, no seu servidor.

Limites e boas práticas

  • 60 chamadas por minuto por chave.
  • Uma chave por lugar de uso. Assim, se uma vazar, você revoga só aquela e o resto continua no ar.
  • Revogar tem efeito imediato: a chamada seguinte já recebe 401.
  • Não bote a chave no navegador, em repositório público nem em aplicativo distribuído.
  • Guarde o id que devolvemos — é por ele que o suporte encontra o pedido.

Changelog

v1 — julho de 2026. Primeira versão pública: save-visit-request com chave por empresa e captacao-org.

Os caminhos, os campos e o formato das respostas desta versão estão congelados. Mudança que quebre integrações existentes sai numa v2 com endereço próprio — o que você escrever hoje continua funcionando.

Travou em algo?

Mande o id do pedido (ou o horário exato da chamada) e o nome da chave para o suporte dentro do app. Com isso a gente acha a requisição no log.