Skip to main content
Na Olie, um formulário é um objeto abstrato: um conjunto de campos que existe por conta própria, sem dono. Ele não pertence a um projeto nem a um cliente — ele é anexado a lugares, e pode estar anexado a vários ao mesmo tempo. O mesmo formulário “Qualificação” pode estar, simultaneamente, no funil de Vendas, na etapa “Proposta enviada” de outro funil e no cadastro de cliente. Em cada um desses lugares ele acumula um conjunto diferente de respostas. Por isso, o form_id sozinho não identifica respostas. A pergunta “quais são as respostas do formulário 19?” não tem resposta única. O formulário 19 tem um conjunto de respostas para cada lugar em que está anexado e para cada registro. O pivot — também chamado de target nos endpoints de escrita — é o objeto que responde à pergunta que falta: onde está esse formulário? É ele que endereça a leitura e a gravação.
Esta página trata de respostas. Criar ou alterar a definição do formulário — os campos, os tipos, as condicionais — é outro endpoint: ver Criar e editar formulários pela API.

Onde um formulário pode estar

O pivot_class diz qual é o tipo de vínculo. Cada tipo exige atributos diferentes para completar o endereço.

Quais objetos aceitam formulário

Só quatro objetos aceitam formulário de objeto, aquele que é configurado uma vez por empresa e passa a valer para todos os registros daquele tipo: Cada um aceita um formulário. A configuração é feita em POST /api/management/set-model-forms, que exige a permissão frame_settings.edit.model_forms.
Squad não aceita formulário. O objeto aparece na tela Formulário dos objetos, mas não tem suporte por trás: enviar App\Models\Squad em set-model-forms devolve erro class_unable_for_forms.
Os outros pivot_class da tabela de endereços (funil, etapa e formulário avulso) não são configuração de objeto. São vínculos internos que a plataforma cria quando o projeto entra no funil, quando chega à etapa ou quando alguém anexa um formulário avulso. Você não cria esses vínculos pela API: apenas os endereça para ler e gravar respostas. O mesmo vale para App\Models\FormPublicationResponse, que endereça a resposta de uma publicação de formulário e pode aparecer no campo model de uma leitura.
pivot_class aceita tanto o nome completo (App\Models\ProjectStepForm) quanto o nome curto (projectstepform, project_step_form, project). O mesmo vale para father_class.

A anatomia do pivot

string
required
O tipo de vínculo. Define quais outros atributos são obrigatórios — veja a tabela acima.
integer
required
Qual formulário será lido ou respondido.
variável
required
Variam conforme o pivot_class. São eles que dizem em qual registro o formulário está: id, ou project_id + funnel_step_id, e assim por diante.
string
O registro de origem — quase sempre o projeto. Serve como conferência: a plataforma verifica se aquele formulário está mesmo naquele lugar daquele registro.Opcional na leitura. Obrigatório na gravação.

Como obter um pivot pronto

Montar o pivot à mão é possível, mas desnecessário — e é onde os erros acontecem. A plataforma entrega o objeto pronto por dois caminhos.

Copiando pela interface

Na aba Formulários de um projeto, cada formulário anexado aparece como um cartão. O menu ⋯ do cartão traz, em Opções avançadas, a opção Copiar pivô como JSON: ela coloca na área de transferência o endereço exato daquele cartão, pronto para colar na requisição.
Cartão do formulário Qualificação do lead, do funil BACKEND, com o menu aberto mostrando os grupos Formulário, Versões e Opções avançadas, este último com Copiar pivô como JSON e Gerar link de resposta

O menu do cartão de formulário, com a opção Copiar pivô como JSON

O número no badge ao lado do título do cartão, como #24, é o form_id. O JSON copiado traz o pivot completo daquele cartão:
Para testar uma chamada, cole o JSON direto no corpo de get-form-answers ou dentro de target em set-form-answers. O mesmo menu aparece nos cartões da aba Funil do projeto. A opção vizinha, Gerar link de resposta, empacota esse mesmo pivot em um link assinado: veja O pivot como link de resposta.

Pelo endpoint de descoberta

Para fazer o mesmo por código, pergunte à plataforma quais formulários existem em um registro. A resposta já vem com os pivots prontos.
{model} aceita project, customer, contact ou frame_relationship.
Resposta
Um grupo vazio significa que não há formulário anexado ali. Cada item da lista já é um pivot válido — copie o objeto inteiro para as chamadas de leitura e escrita.
O item de model_form traz related_model_attribute_id além de id, com o mesmo valor. Só o id é usado como endereço; o outro campo é resíduo do formato de descoberta e pode ser ignorado.

Ler respostas

Aqui os campos do pivot vão na raiz do corpo, e father_class / father_id são opcionais.
A resposta traz um item por campo do formulário, respondido ou não:
integer
O identificador do campo do formulário. É esse valor que você usa para gravar a resposta.
mixed
A resposta gravada, ou null quando o campo nunca foi respondido naquele endereço.
string
O pivot_class que produziu a resposta — útil para conferir que você leu o endereço certo.

Ler respostas de muitos projetos

O get-form-answers lê um endereço por chamada, e nenhuma rota devolve em JSON as respostas de todos os formulários de vários projetos de uma vez. Para ler em volume, escolha um destes caminhos:

Gravar respostas

Na escrita o pivot vai dentro de target, e father_class / father_id passam a ser obrigatórios.
O father_class e o father_id dependem do pivot_class. Nos formulários de objeto, eles apontam para o próprio registro. No funil, na etapa e no formulário avulso, eles apontam para o projeto. Veja o target de cada tipo:
array
required
Cada item precisa de id — o identificador do campo, obtido na leitura — e answer. Campos não enviados permanecem como estavam. O formato de answer depende do tipo do campo. Ver Formato da resposta de cada campo.
Campo do tipo anexo tem um passo a mais: o arquivo sobe antes, em outro endpoint, e o objeto devolvido é que vira o answer. Ver Anexos em resposta de formulário.
A resposta devolve o formulário inteiro já com os valores gravados, na chave edges, com os itens no mesmo formato de answers da leitura.
Ler e gravar são endereçados de formas diferentes: leitura na raiz do corpo, escrita dentro de target. Reaproveitar o mesmo JSON entre os dois endpoints sem esse ajuste é o erro mais comum.

Erros comuns

Cada pivot_class tem seus atributos obrigatórios. Enviar ProjectFunnelAssignment sem project_funnel_id, por exemplo, devolve HTTP 422 com o atributo que faltou em validation:
Para resolver, acrescente o atributo listado em validation. Os atributos de cada tipo estão na tabela de Onde um formulário pode estar.
A API responde com HTTP 422 e essa message quando o registro de origem (father_class e father_id) não tem esse formulário nesse lugar. Acontece quando o form_id, a etapa ou o funil não batem com o registro de origem. Por exemplo, uma etapa que não pertence a nenhum funil daquele projeto.Para resolver, copie o pivot pela interface ou consulte GET /api/management/dynamic-forms/{model}/{model_id}.
A API responde com essa message quando o form_id não existe na empresa autenticada. Para resolver, confira o ID na listagem de formulários (GET /api/management/get-forms) ou use um pivot obtido pelo endpoint de descoberta.

O mesmo pivot na sintaxe avançada

Dentro de uma automação, a consulta get_form_answers recebe exatamente esse objeto no parâmetro pivot. Ele vem pronto da consulta project_dynamic_forms:

Funções de consulta

Como usar query nas automações, com todas as consultas disponíveis.
Empacota um pivot em um link assinado, para alguém responder o formulário sem acessar a plataforma. A resposta traz decode_url (carrega o formulário) e reply_url (recebe as respostas).
Atenção ao nome: neste endpoint, pivot_class é o objeto pivot inteiro, e não a string do tipo de vínculo. É o mesmo nome com dois significados diferentes.
date
Quando o link deixa de valer. Precisa ser uma data futura: uma data no passado é recusada com 422. Sem ele, o padrão é 24 horas a partir da geração.
boolean
default:"false"
Invalida o link assim que ele for usado para responder.