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.
Cada chave pertence a uma empresa. É por isso que você não precisa informar qual empresa é: nós descobrimos pela chave.
Autenticação
Mande a chave no cabeçalho x-api-key. Nenhum outro cabeçalho de autenticação é necessário.
x-api-key: sk_live_…
Content-Type: application/jsonSe preferir, o formato Bearer sk_live_… também é aceito no mesmo cabeçalho — os dois valem a mesma coisa.
Criar solicitação de visita
Cria o pedido na sua conta e devolve o identificador dele.
https://pqceyzucuydbjnjxrduh.supabase.co/functions/v1/save-visit-request| Campo | Tipo | Obrigatório | Observação |
|---|---|---|---|
nome | string | sim | Mínimo 2 caracteres. |
email | string | sim | Precisa ter formato de e-mail. |
telefone | string | sim | Mínimo 10 caracteres. Pode vir com máscara: (47) 99999-9999. |
cidade | string | sim | Usada no rodízio: quem atende aquela cidade recebe o lead. |
data_agendada | string | sim | Formato AAAA-MM-DD. Outro formato é recusado pelo banco (erro 500). |
horario_agendado | string | sim | Texto livre, como "14:00" ou "Manhã". |
endereco | string | não | Endereço da visita. |
complemento | string | não | Apartamento, bloco, referência. |
mensagem | string | não | O que o cliente escreveu. |
atribuicao | objeto | não | Origem 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
# 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.
https://pqceyzucuydbjnjxrduh.supabase.co/functions/v1/captacao-orgcurl -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 -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)
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.
<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ê vê 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
idque 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.