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.

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.
Os formulários de objeto (projeto, cliente, contato e usuário) são configurados por conta: cada tipo de objeto tem no máximo um formulário anexado, e ele vale para todos os registros daquele tipo. Já funil, etapa e avulso são vínculos individuais.
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 do cartão — #24 na imagem — é o form_id. O JSON copiado traz o pivot completo daquele cartão:
É o caminho mais rápido 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.

Gravar respostas

Na escrita o pivot vai dentro de target, e father_class / father_id passam a ser obrigatórios.
array
required
Cada item precisa de id — o identificador do campo, obtido na leitura — e answer. Campos não enviados permanecem como estavam.
A resposta devolve o formulário inteiro já com os valores gravados, no mesmo formato de answers.
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 422:
O father informado 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.Resolva copiando o pivot pela interface ou consultando GET /dynamic-forms/{model}/{model_id}.
O form_id não existe na conta autenticada.

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. Sem ele, o padrão é 24 horas.
boolean
default:"false"
Invalida o link assim que ele for usado para responder.