LPLeadProof

Cognito Forms CRM delivery

Make Cognito Forms webhook retries safe for the CRM.

Keep Cognito Forms' documented retry window duplicate-safe, forward only approved contact fields, and retain a LeadProof receipt for the final CRM handoff.

Protect 25 live leads free →Start Builder · $49/monthAudit this workflow
Paid plan uses secure Stripe checkout · plan assigned after verified payment · activate with the checkout email
THE FAILURE GAP

A successful automation run is not proof of delivery.

Cognito Forms can retry a webhook up to 15 times over 72 hours after most 4xx or 5xx responses, and its JSON webhook can contain the complete form entry. Without a stable entry identity and strict field allowlist, one temporary adapter failure can create duplicate CRM work or forward documents and unrelated response data that the destination never needed.

Cognito Forms submit webhook -> private adapter -> durable queue -> LeadProof -> CRM
01

Provider retries can duplicate side effects

The same entry may arrive repeatedly during the documented retry window, so every attempt must remain one delivery identity.

02

Complete entries exceed CRM need

Cognito Forms can include every entry field and short-lived document links; a lead adapter should select only the approved contact fields.

03

Webhook acceptance is not CRM proof

A 2xx from the receiving adapter should mean the mapped event is durable, not merely that the request reached application memory.

Implementation

Put LeadProof in the delivery path.

Keep the tools that create and process the lead. Standardize only the fragile handoff between them.

Platform reference: Cognito Forms webhook documentationOpen sandbox instructions →
  1. Configure only the Cognito Forms Submit Entry Endpoint for this lead workflow and point it to a dedicated HTTPS adapter path protected by a long random route token.
  2. Validate the route token before parsing, require the Cognito entry id, and copy only the approved name, email, and phone JSON names.
  3. Enqueue the compact mapped lead before returning 202 so Cognito Forms does not retry a request that has already become durable.
  4. Use the Cognito entry id as the LeadProof Idempotency-Key on every queued attempt, then retain the LeadProof receipt ID with the source event or operator log.
POSThttps://leadproof.jessesay.chatgpt.site/api/v1/leads
import crypto from "node:crypto";

function sameSecret(supplied, expected) {
  if (!supplied || !expected) return false;
  const left = Buffer.from(supplied);
  const right = Buffer.from(expected);
  return left.length === right.length && crypto.timingSafeEqual(left, right);
}

app.post(
  "/cognito/submission/:token",
  (req, res, next) => {
    if (
      !sameSecret(
        req.params.token,
        process.env.COGNITO_WEBHOOK_ROUTE_TOKEN
      )
    ) {
      return res.sendStatus(404);
    }
    return next();
  },
  express.json({ limit: "64kb" }),
  async (req, res) => {
    const entryId = req.body?.id;
    const lead = {
      name: typeof req.body?.name === "string" ? req.body.name : undefined,
      email: typeof req.body?.email === "string" ? req.body.email : undefined,
      phone: typeof req.body?.phone === "string" ? req.body.phone : undefined
    };
    if (typeof entryId !== "string" || !lead.name || !lead.email) {
      await recordRejectedEntry({
        source: "cognito_forms",
        reason: "missing_approved_fields"
      });
      return res.sendStatus(204);
    }

    await deliveryQueue.send({ entryId, lead });
    return res.sendStatus(202);
  }
);

export async function deliverCognitoLead({ entryId, lead }) {
  const response = await fetch(
    "https://leadproof.jessesay.chatgpt.site/api/v1/leads",
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.LEADPROOF_API_KEY}`,
        "Content-Type": "application/json",
        "Idempotency-Key": entryId
      },
      body: JSON.stringify({
        destination: process.env.CRM_WEBHOOK_URL,
        ...lead,
        source: "cognito_forms"
      })
    }
  );

  if (!response.ok) throw new Error("Lead delivery failed");
  const delivery = await response.json();
  await persistReceipt(entryId, delivery.receipt?.id);
}

Questions

What teams ask before adding LeadProof.

Why use the Cognito entry id?

Cognito Forms includes an id in its documented JSON examples. Using that source identity keeps repeated webhook attempts attached to one LeadProof delivery event.

Why return 202 after queueing?

Cognito Forms documents retries for most 4xx and 5xx responses. A success response should be sent only after the mapped event is durable enough for the worker to finish later.

Should documents and every form answer be forwarded?

No. Map only the fields authorized for CRM delivery. The adapter example excludes document links, uploads, signatures, payments, and unrelated form answers.

FREE · NO SIGNUP

See the gaps in your real workflow.

Get an explainable risk score, prioritized fixes, and the right LeadProof plan.

Protect 25 live leads free →Run the reliability auditStart Builder · $49/month