splitforms.com
All articles/ INTEGRATIONS10 MIN READPublished June 21, 2026

How to Send Form Submissions to Salesforce (No Zapier, 2026)

Route HTML form submissions into Salesforce as Leads without Zapier — own your form HTML, deliver via a signed splitforms webhook and a small proxy to the Salesforce REST API.

✶ Written by
splitforms.com / blog

Founder of splitforms — the form backend API for developers. Writes about form UX, anti-spam, and shipping web apps without backend code.

Why route around Web-to-Lead

Salesforce is a great system of record. Salesforce Web-to-Lead is a serviceable but rigid way to get web leads into it: a fixed hidden-field format, field IDs instead of readable names, weak spam handling, and no submission dashboard outside Salesforce. When a lead fails a validation rule it can disappear with no trace.

Owning your form HTML and routing through splitforms fixes the form-side problems — you get a Tailwind-styled form you control, an AI spam classifier, email notifications, and a dashboard you can audit — while Salesforce stays the system of record. A small stateless proxy translates the signed webhook into a REST API Lead create.

Step 1 — Create a Connected App and get OAuth credentials

In Salesforce Setup, search App ManagerNew Connected App.

  1. Name it "splitforms webhook". Enable OAuth Settings.
  2. Set a callback URL (any HTTPS URL for the client-credentials flow), and add the api scope ("Manage user data via APIs").
  3. Enable the Client Credentials Flow and assign a run-as integration user with permission to create Leads.
  4. Save, then copy the Consumer Key and Consumer Secret. Note your instance URL (e.g. https://yourorg.my.salesforce.com).

Store the key, secret, and instance URL as environment variables on your proxy host — never in the browser.

Step 2 — Map form fields to Lead fields

Salesforce Leads have standard fields — FirstName, LastName, Email, Company, Phone, LeadSource, Description — plus any custom fields (suffixed __c). LastName and Company are required on the standard Lead object, so make sure your form supplies them (or default Company to something like "[Web]" for B2C).

A Lead create request looks like this:

POST https://yourorg.my.salesforce.com/services/data/v60.0/sobjects/Lead
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "FirstName":  "Ada",
  "LastName":   "Lovelace",
  "Email":      "ada@example.com",
  "Company":    "Lovelace Industries",
  "Phone":      "+1-555-0100",
  "LeadSource": "Web",
  "Description": "Hi — I'd like a 15-min demo.",
  "UTM_Source__c":   "google",
  "UTM_Campaign__c": "spring-2026"
}

Step 3 — The splitforms → Salesforce proxy

splitforms delivers a signed webhook to any HTTPS endpoint; the proxy holds the Salesforce credentials, gets a token via the client-credentials flow, and creates the Lead. Here's a Cloudflare Worker version:

export default {
  async fetch(req, env) {
    if (req.method !== "POST") return new Response("Method Not Allowed", { status: 405 });

    // 1. (Recommended) verify the splitforms HMAC signature header here.

    const submission = await req.json();
    const f = submission.data ?? submission; // form fields

    // 2. Get a Salesforce access token (client-credentials flow)
    const tokenRes = await fetch(`${env.SF_INSTANCE_URL}/services/oauth2/token`, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams({
        grant_type: "client_credentials",
        client_id: env.SF_CLIENT_ID,
        client_secret: env.SF_CLIENT_SECRET,
      }),
    });
    const { access_token } = await tokenRes.json();

    // 3. Create the Lead
    const lead = {
      FirstName: f.first_name ?? (f.name ?? "").split(" ")[0],
      LastName:  f.last_name  ?? (f.name ?? "Web Lead").split(" ").slice(1).join(" ") || "Web Lead",
      Email:     f.email,
      Company:   f.company ?? "[Web]",
      Phone:     f.phone,
      LeadSource: "Web",
      Description: f.message ?? f.description,
    };

    const sfRes = await fetch(
      `${env.SF_INSTANCE_URL}/services/data/v60.0/sobjects/Lead`,
      {
        method: "POST",
        headers: {
          Authorization: `Bearer ${access_token}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(lead),
      }
    );

    if (!sfRes.ok) return new Response(await sfRes.text(), { status: 502 });
    return new Response("ok", { status: 200 });
  },
};

Deploy the Worker, then paste its URL into your form's webhook settings in the splitforms dashboard. To prevent duplicate Leads, enable Salesforce Duplicate Rules or switch the create call to an upsert against an external-ID field. Always verify the webhook signature — see sending form data to a webhook and the docs.

Step 4 — The form

Your public form only ever talks to splitforms with the public access key. Swap YOUR_ACCESS_KEY for the one from your free account.

<form action="https://splitforms.com/api/submit" method="POST">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
  <input name="name" required placeholder="Full name" />
  <input name="email" type="email" required placeholder="Work email" />
  <input name="company" placeholder="Company" />
  <input name="phone" type="tel" placeholder="Phone" />
  <textarea name="message" placeholder="How can we help?"></textarea>

  <!-- attribution -->
  <input type="hidden" name="utm_source" value="" />
  <input type="hidden" name="source_page" value="" />

  <!-- honeypot -->
  <input type="checkbox" name="botcheck" style="display:none" tabindex="-1" autocomplete="off" />
  <button type="submit">Request a demo</button>
</form>

What to do next

FAQ

Why not just use Salesforce Web-to-Lead?

Web-to-Lead works, but it posts to a Salesforce-hosted endpoint with a fixed hidden-field format, no real spam protection beyond optional reCAPTCHA, no dashboard of submissions outside Salesforce, and field names you don't control. If a lead fails validation it can silently vanish. Owning your form HTML and routing through splitforms gives you spam filtering, a submission dashboard you can audit, email notifications, and retry-able delivery — then a small proxy creates the Lead via the REST API. You keep Salesforce as the system of record without its form limitations.

Do I need a paid Salesforce edition for API access?

API access is included on Enterprise, Unlimited, and Developer editions, and available as an add-on on some others. If you can create a Connected App and generate OAuth credentials, you can use this method. The free Developer Edition is perfect for testing the integration before you wire it into production.

Is it safe to call the Salesforce API from the browser?

No — and you shouldn't. The Salesforce access token is a secret and must never live in client-side code. That's exactly why this setup uses a small server-side proxy: the browser posts to splitforms (with only the public access key), splitforms fires a signed webhook to your proxy, and the proxy holds the Salesforce credentials and creates the Lead. The secret never touches the page.

Will duplicate submissions create duplicate Leads?

By default the REST API create endpoint will make a new Lead each time. To avoid duplicates, either enable Salesforce Duplicate Rules on the Lead object, or have your proxy do an upsert against an external ID field (for example a hashed email). The proxy example in this guide shows where to add that check.

Can I map UTM parameters and the source page into Salesforce?

Yes. Add hidden inputs to your form (utm_source, utm_campaign, source_page) and populate them with a one-line script. They arrive in the splitforms webhook payload and your proxy maps them to Lead fields (standard LeadSource, or custom fields you create). That gives your sales team full attribution on every web lead.

About the author
✻ ✻ ✻

Get your free contact form API key in 60 seconds.

500 free form submissions per month. No credit card. No SDK, no PHP, no plugin. Drop one POST endpoint in your form and submissions land in your dashboard. Starter adds inbox delivery.

Generate access key →Read the docs
founders pricing locked in · early access open