REST API · JSON · API Key

Zavvi API

Integre pesquisas de satisfação ao seu sistema. Crie pesquisas, colete respostas e analise resultados programaticamente.

Base URL
https://www.zavvi.com.br/api/v1

Autenticação

A API utiliza chaves de acesso (API Keys) que você mesmo gera no painel, em API → API Keys. Envie sua chave no header de todas as requisições autenticadas.

Como obter sua API Key

  1. Crie uma conta em zavvi.app e confirme seu e-mail (chaves de contas sem e-mail confirmado recebem 403)
  2. No painel, acesse API → API Keys em https://www.zavvi.com.br/app/api/keys — o painel de API é liberado para assinantes do plano Escala
  3. Clique em criar chave, informe um nome (obrigatório) e, se quiser, uma data de expiração (opcional, precisa ser posterior a hoje)
  4. A chave completa aparece uma única vez logo após a criação — copie e guarde. Na listagem só ficam visíveis os primeiros caracteres
  5. Utilize a chave no header X-API-Key de todas as requisições

Exemplo de requisicao

cURL
curl -X GET https://www.zavvi.com.br/api/v1/surveys \
  -H "X-API-Key: sua_chave_aqui" \
  -H "Accept: application/json"

Erros de autenticacao

Sem chave401
{
  "message": "API key required. Use header X-API-Key."
}
Chave invalida401
{
  "message": "Invalid or expired API key."
}
Importante: A API Key está vinculada à sua conta. Todas as operações (criar pesquisas, ver respostas) sao executadas no contexto do seu usuário. Não compartilhe sua chave. Caso suspeite de vazamento, você mesmo pode desativar ou excluir a chave em API → API Keys e gerar uma nova na hora.

Headers obrigatórios

HeaderValorDescrição
X-API-KeystringobrigatórioSua chave de API (48 caracteres)
Acceptstringrecomendadoapplication/json
Content-TypestringPOST/PUTapplication/json

Pesquisas

Gerencie pesquisas de satisfação. Todas as rotas requerem X-API-Key. Pesquisas são identificadas por UUID.

GET /api/v1/surveys API Key Listar pesquisas

Retorna as pesquisas do usuário autenticado, das mais recentes para as mais antigas. O resultado é paginado: use per_page (padrão 15, máximo 100) e page na query string. A resposta traz também os blocos links e meta da paginação.

Resposta

JSON200 OK
{
  "data": [
    {
      "id": "a1b2c3d4-e5f6-...",
      "title": "Satisfacao no Atendimento",
      "status": "published",
      "url": "https://www.zavvi.com.br/s/a1b2c3d4-e5f6-...",
      "questions_count": 8,
      "responses_count": 342,
      "created_at": "2026-01-15T10:30:00Z"
    }
  ]
}
GET /api/v1/surveys/{uuid} API Key Detalhes da pesquisa

Retorna os detalhes de uma pesquisa específica. A lista de questões não vem neste endpoint — o objeto traz apenas os contadores questions_count e responses_count, além de identificação, textos e cores. Para obter as questões, use GET /surveys/{uuid}/questions.

Resposta

JSON200 OK
{
  "data": {
    "id": "a1b2c3d4-e5f6-...",
    "title": "Satisfacao no Atendimento",
    "status": "published",
    "url": "https://www.zavvi.com.br/s/a1b2c3d4-e5f6-...",
    "welcome_message": "Ola! Leva 1 minuto.",
    "goodbye_text": "Obrigado pela participacao!",
    "redirect_url": null,
    "visibility": true,
    "is_template": false,
    "notify_new_responses": true,
    "color": "#7c3aed",
    "question_color": "#ffffff",
    "answer_color": "#ffffff",
    "button_color": "#7c3aed",
    "button_text_color": "#ffffff",
    "background_color": "#0b0b12",
    "logo": null,
    "questions_count": 8,
    "responses_count": 342,
    "created_at": "2026-01-15T10:30:00Z",
    "updated_at": "2026-01-20T09:00:00Z"
  }
}
POST /api/v1/surveys API Key Criar pesquisa

Cria uma nova pesquisa. Requer assinatura ativa e limite de pesquisas não atingido. Envie sempre welcome_message e goodbye_text junto com o título: as duas colunas não aceitam valor nulo no banco e a criação só com title falha.

Parâmetros

CampoTipoDescrição
titlestringobrigatórioTítulo da pesquisa (max 255)
welcome_messagestringenvie sempreMensagem de boas-vindas — a validação aceita omitir, mas o banco não tem valor padrão para esta coluna
goodbye_textstringenvie sempreMensagem de agradecimento — mesma observação de welcome_message
visibilitybooleanopcionalPesquisa publicada (default: true — sem informar nada ela já nasce publicada)
redirect_urlstringopcionalURL válida para redirecionar ao final
notify_new_responsesbooleanopcionalNotificar por e-mail a cada nova resposta
color, question_color, answer_color, button_color, button_text_color, background_colorstringopcionalCores da pesquisa (max 50 caracteres cada)
PUT /api/v1/surveys/{uuid} API Key Atualizar pesquisa

Atualiza uma pesquisa existente. Apenas o dono pode atualizar.

DEL /api/v1/surveys/{uuid} API Key Deletar pesquisa

Remove permanentemente uma pesquisa e todas as suas questões e respostas.

POST /api/v1/surveys/{uuid}/duplicate API Key Duplicar pesquisa

Cria uma copia da pesquisa com todas as questões. A copia inicia como rascunho com zero respostas.

Questoes

Gerencie questões dentro de uma pesquisa. Tipos aceitos pela API: multiple-choices, yes-no, dropdown, short-text, long-text, number, email, phone, date, rating, slider

Atenção: nps, csat e ces não são tipos válidos na API — enviá-los retorna 422. Para uma pergunta de recomendação de 0 a 10, use o tipo rating: é sobre ele que o endpoint de analytics calcula o NPS.
GET /api/v1/surveys/{uuid}/questions API Key Listar questões

Retorna todas as questões da pesquisa ordenadas por posição (sem paginação). O campo choices só é preenchido para os tipos multiple-choices, yes-no, dropdown e slider; nos demais tipos ele vem null.

Resposta

JSON200 OK
{
  "data": [
    {
      "id": 1,
      "survey_id": 7,
      "type": "rating",
      "text": "De 0 a 10, quanto voce recomendaria?",
      "position": 1,
      "visibility": true,
      "is_required": true,
      "attributes": { "scale": 10 },
      "choices": null,
      "image": null
    }
  ]
}
POST /api/v1/surveys/{uuid}/questions API Key Criar questão

Adiciona uma questão à pesquisa. Requer limite de questões não atingido.

Parâmetros

CampoTipoDescrição
textstringobrigatórioTexto da questão (max 1000)
typestringobrigatórioTipo (ver lista acima). Valor fora da lista retorna 422
positionintegeropcionalOrdem de exibicao (default: última posição)
visibilitybooleanopcionalQuestão visível na pesquisa (default: true)
is_requiredbooleanopcionalResposta obrigatoria (default: true)
attributesobjectopcionalConfiguracoes especificas do tipo (choices, scale, etc.)
imagestringopcionalCaminho da imagem da questão
PUT /api/v1/questions/{id} API Key Atualizar questão

Atualiza uma questão existente. A rota é rasa: use o ID numérico da questão direto em /api/v1/questions/{id}, sem o UUID da pesquisa. Os campos aceitos são os mesmos da criação, todos opcionais (text e type não podem ser enviados vazios).

DEL /api/v1/questions/{id} API Key Deletar questão

Remove uma questão. Assim como no update, a rota é rasa e usa apenas o ID numérico da questão. Retorna 204 sem corpo.

Respostas

Colete e consulte respostas de pesquisas. A submissao e publica (nao requer autenticacao).

GET /api/v1/surveys/{uuid}/responses API Key Listar respostas

Retorna as respostas de uma pesquisa uma linha por questão respondida — não vêm agrupadas por respondente. Para reconstruir o questionário de cada pessoa, agrupe as linhas pelo campo attendee_id, que identifica o respondente. Cada linha já traz a questão correspondente embutida em question.

O resultado é paginado e ordenado da resposta mais recente para a mais antiga: use per_page (padrão 50) e page na query string.

Resposta

JSON200 OK
{
  "data": [
    {
      "id": 981,
      "survey_id": 7,
      "question_id": 1,
      "attendee_id": 4512,
      "response": "9",
      "question": {
        "id": 1,
        "type": "rating",
        "text": "De 0 a 10, quanto voce recomendaria?"
      },
      "created_at": "2026-03-18T14:30:00Z",
      "updated_at": "2026-03-18T14:30:00Z"
    }
  ],
  "links": { "..." },
  "meta": { "..." }
}
POST /api/v1/surveys/{uuid}/responses Público Submeter respostas

Submete respostas para uma pesquisa. Rate limit: 10 requisições/minuto por IP. A pesquisa precisa estar publicada — caso contrário a API responde 403 com "This survey is not available.". Cada chamada cria um novo respondente com todas as respostas enviadas no corpo.

Parâmetros

CampoTipoDescrição
responsesarrayobrigatórioLista de respostas (pelo menos 1 item). Não é um objeto/mapa
responses[].question_idintegerobrigatórioID numérico da questão (o mesmo id devolvido em GET /surveys/{uuid}/questions)
responses[].responsestringobrigatórioValor respondido, sempre como string — inclusive notas numéricas ("9")

Exemplo

Request Body
{
  "responses": [
    { "question_id": 1, "response": "9" },
    { "question_id": 2, "response": "Atendimento excelente!" },
    { "question_id": 3, "response": "Sim" }
  ]
}

Resposta

JSON200 OK
{
  "data": [
    {
      "id": 981,
      "survey_id": 7,
      "question_id": 1,
      "attendee_id": 4512,
      "response": "9",
      "created_at": "2026-03-18T14:30:00Z",
      "updated_at": "2026-03-18T14:30:00Z"
    }
  ]
}
Atenção: enviar responses como objeto ({"1": "9"}) retorna 422. IDs de questão que existem mas pertencem a outra pesquisa são ignorados em silêncio: não geram erro e não aparecem na resposta. IDs inexistentes reprovam a validação com 422.

Analytics & Planos

Dados analíticos das pesquisas e planos disponíveis.

GET /api/v1/surveys/{uuid}/analytics API Key Dados analíticos

Retorna os totais da pesquisa, a taxa de conclusão e um detalhamento por questão. A resposta não é embrulhada em data — os campos vêm na raiz do JSON. Não existe um bloco scores com nps/csat/ces: o único indicador calculado é o NPS por questão, e apenas para questões do tipo rating.

Campos da raiz

CampoTipoDescrição
survey_idstringUUID da pesquisa
titlestringTítulo da pesquisa
total_responsesintegerTotal de respostas registradas na pesquisa
total_attendeesintegerTotal de respondentes
total_questionsintegerTotal de questões
completion_ratefloat% de respondentes que responderam todas as questões visíveis. Vem null quando não há respondentes ou questões visíveis
questionsarrayDetalhamento por questão (ver abaixo)

Campos de cada item de questions

CampoTipoDescrição
question_idintegersempreID da questão
textstringsempreTexto da questão
typestringsempreTipo da questão
response_countintegersempreQuantas respostas a questão recebeu
average_ratingfloatsó ratingMédia das notas numéricas maiores que zero
npsintegersó ratingNPS da questão, arredondado: % de notas ≥ 9 menos % de notas ≤ 6, considerando escala de 1 a 10. Só aparece quando há pelo menos uma nota numérica
distributionobjectsó escolhaContagem por alternativa, da mais escolhida para a menos. Presente em multiple-choices, yes-no e dropdown

Resposta

JSON200 OK
{
  "survey_id": "a1b2c3d4-e5f6-...",
  "title": "Satisfacao no Atendimento",
  "total_responses": 342,
  "total_attendees": 405,
  "total_questions": 8,
  "completion_rate": 84.5,
  "questions": [
    {
      "question_id": 1,
      "text": "De 0 a 10, quanto voce recomendaria?",
      "type": "rating",
      "response_count": 120,
      "average_rating": 8.74,
      "nps": 72
    },
    {
      "question_id": 2,
      "text": "Voce voltaria a comprar?",
      "type": "yes-no",
      "response_count": 118,
      "distribution": { "Sim": 101, "Nao": 17 }
    }
  ]
}
GET /api/v1/plans Público Listar planos

Retorna todos os planos disponíveis com preços e limites.

Resposta

JSON200 OK
{
  "data": [
    {
      "id": 1,
      "title": "Gratuito",
      "price": 0,
      "interval": "monthly",
      "is_free": true,
      "limits": {
        "survey_count": 3,
        "question_count_per_survey": 10,
        "response_count_per_survey": 100
      }
    },
    {
      "id": 2,
      "title": "Starter",
      "price": 49.00,
      "is_free": false,
      "limits": { "..." }
    }
  ]
}

Limites e Erros

Informações sobre rate limiting e códigos de erro.

Rate Limits

Com API Key60 req/min por conta
Submissão pública10 req/min por IP
Sem API Key60 req/min por IP

Códigos de Erro

200 Sucesso
201 Recurso criado
202 Envio em massa enfileirado
204 Removido (sem corpo)
401 Não autenticado
403 Sem permissão
404 Não encontrado
422 Validação falhou
429 Rate limit excedido

Plano Escala

Endpoints exclusivos para assinantes do plano Escala (enterprise). Requerem X-API-Key de um usuário com plano Escala ativo.

Plano Escala — Estes endpoints retornam 403 para usuários em outros planos. Fazer upgrade →
TAGS Tags Dinamicas Personalize pesquisas com dados do seu sistema

Tags dinamicas permitem personalizar o texto da pesquisa para cada destinatario. Use placeholders no formato {{NOME_DA_TAG}} nos campos da pesquisa, e envie os valores correspondentes no campo context da API.

Como Funciona

1
Configure a pesquisa

No painel, crie uma Pesquisa API e use tags nos campos de boas-vindas e perguntas:

Mensagem de boas-vindas: {{NOME_CLIENTE}} - Pesquisa de Satisfacao - Televendas 📦
Pedido: {{NRO_PEDIDO}} 📝
2
Envie via API com o context

No campo context, passe os valores das tags:

Request Body
{
  "channel": "email",
  "recipient": {
    "name": "Joao Silva",
    "email": "joao@email.com"
  },
  "context": {
    "NOME_CLIENTE": "Joao Silva",
    "NRO_PEDIDO": "PED-2026-00142"
  },
  "subject": "{{NOME_CLIENTE}}, como foi seu pedido {{NRO_PEDIDO}}?"
}
3
O destinatario ve a pesquisa personalizada

As tags sao substituidas em todos os lugares:

Joao Silva - Pesquisa de Satisfacao - Televendas 📦
Pedido: PED-2026-00142 📝

Onde as tags funcionam

CampoDescricao
welcome_messageMensagem de boas-vindas exibida ao abrir a pesquisa
Texto das perguntasO texto de cada pergunta — somente no modo de exibição conversacional. No modo clássico o texto da pergunta é exibido cru, sem substituição de tags
subjectAssunto do e-mail de convite (passado no envio via API)

Regras

  • Tags usam o formato {{NOME_TAG}} — apenas letras, numeros e underscore entre as chaves (sem espacos, acentos ou hifens)
  • As tags sao livres: voce pode usar qualquer nome que quiser
  • Se uma tag nao tiver valor no context, ela permanece no texto exatamente como foi escrita — o destinatario ve {{NOME_TAG}}. Envie sempre todas as tags usadas na pesquisa, mesmo que com string vazia
  • A unica situacao em que as tags somem do texto e quando o acesso nao tem nenhum context associado e a pesquisa e do tipo Pesquisa API: ai todas as tags sao apagadas de uma vez. Em pesquisas comuns sem context, elas continuam visiveis
  • Os valores do context precisam ser strings de ate 500 caracteres — numeros e objetos aninhados sao recusados com 422
  • As tags sao case-sensitive: NOME e nome sao tags diferentes
  • Cada destinatario recebe um link unico com seus dados personalizados

Tags no Envio em Massa

No endpoint de envio em massa (POST /send/bulk), cada destinatario pode ter seu proprio context:

Bulk com tags individuais
{
  "channel": "email",
  "subject": "{{NOME_CLIENTE}}, avalie seu pedido",
  "recipients": [
    {
      "name": "Joao Silva",
      "email": "joao@email.com",
      "context": {
        "NOME_CLIENTE": "Joao Silva",
        "NRO_PEDIDO": "PED-001"
      }
    },
    {
      "name": "Maria Santos",
      "email": "maria@email.com",
      "context": {
        "NOME_CLIENTE": "Maria Santos",
        "NRO_PEDIDO": "PED-002"
      }
    }
  ]
}

Painel de Acompanhamento

Todos os envios via API sao rastreados e podem ser acompanhados no painel API do dashboard, incluindo:

  • Status de cada envio (pendente, enviado, entregue, falha)
  • Dados do context enviado para cada destinatario
  • Taxa de conclusao (quem abriu e respondeu a pesquisa)
  • Possibilidade de reenvio para envios que falharam
POST /api/v1/surveys/{uuid}/send Escala Enviar pesquisa

Envia uma pesquisa para um destinatário por e-mail ou WhatsApp. Use o campo context para passar valores das tags dinamicas configuradas na pesquisa. O envio é síncrono.

Parâmetros

CampoTipoDescrição
channelstringobrigatórioemail ou whatsapp
recipient.namestringobrigatórioNome do destinatário
recipient.emailstringse emailE-mail do destinatário
recipient.phonestringse whatsappTelefone internacional (ex: +5511999999999)
contextobjectopcionalDados contextuais livres (chave-valor) para personalizar a mensagem. Cada valor precisa ser string de até 500 caracteres
subjectstringopcionalAssunto do e-mail (ignorado para WhatsApp)

Exemplo

Request Body
{
  "channel": "email",
  "recipient": {
    "name": "Carlos Eduardo",
    "email": "carlos@email.com"
  },
  "context": {
    "NOME_CLIENTE": "Carlos Eduardo",
    "NRO_PEDIDO": "PED-2026-00142"
  },
  "subject": "{{NOME_CLIENTE}}, como foi seu pedido {{NRO_PEDIDO}}?"
}

Resposta

JSON201 Created
{
  "data": {
    "id": 123,
    "channel": "email",
    "recipient": "carlos@email.com",
    "status": "sent",
    "sent_at": "2026-03-18T14:30:00Z",
    "attendee_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}

Status

201 403 422
POST /api/v1/surveys/{uuid}/send/bulk Escala Envio em massa

Envia pesquisas para múltiplos destinatários de uma vez. Os envios são enfileirados e processados em background. Máximo de 500 destinatários por requisição. Um canal por request.

Parâmetros

CampoTipoDescrição
channelstringobrigatórioemail ou whatsapp
subjectstringopcionalAssunto do e-mail (aplicado a todos)
recipientsarrayobrigatórioLista de destinatários (max 500)
recipients[].namestringobrigatórioNome do destinatário
recipients[].emailstringse emailE-mail do destinatário
recipients[].phonestringse whatsappTelefone internacional
recipients[].contextobjectopcionalDados contextuais por destinatário. Cada valor precisa ser string de até 500 caracteres

Exemplo

Request Body
{
  "channel": "email",
  "subject": "Como foi sua experiência?",
  "recipients": [
    {
      "name": "Carlos Eduardo",
      "email": "carlos@email.com",
      "context": { "NOME_CLIENTE": "Carlos Eduardo", "NRO_PEDIDO": "PED-001" }
    },
    {
      "name": "Maria Silva",
      "email": "maria@email.com",
      "context": { "NOME_CLIENTE": "Maria Silva", "NRO_PEDIDO": "PED-002" }
    }
  ]
}

Resposta

JSON202 Accepted
{
  "data": {
    "batch_id": "batch_abc123xyz456",
    "channel": "email",
    "total": 2,
    "status": "queued",
    "message": "2 envios foram enfileirados para processamento."
  }
}

Status

202 403 422
GET /api/v1/surveys/{uuid}/qrcode Escala QR Code da pesquisa

Retorna o QR Code da pesquisa em formato PNG (base64) ou SVG.

Query Params

ParamTipoDescrição
formatstringopcionalpng (default) ou svg
sizeintegeropcional100-1000 pixels (default: 300)

Exemplo

cURL
curl -X GET https://www.zavvi.com.br/api/v1/surveys/{uuid}/qrcode?format=png&size=400 \
  -H "X-API-Key: sua_chave_aqui" \
  -H "Accept: application/json"

Resposta

JSON200 OK
{
  "data": {
    "survey_id": "a1b2c3d4-e5f6-...",
    "survey_url": "https://www.zavvi.com.br/s/a1b2c3d4-e5f6-...",
    "format": "png",
    "size": 400,
    "qrcode": "data:image/png;base64,iVBORw0KGgo..."
  }
}

Status

200 403 422