Notion as a CRM for Form Submissions: A Laravel Workflow | FilaForms                                 [ ![Filaforms Logo](https://filaforms.app/logo.svg)FilaForms

 ](https://filaforms.app)  [ Features ](https://filaforms.app#features) [ Pricing ](https://filaforms.app#pricing) [ Blog ](https://filaforms.app/blog) [ Documentation ](https://docs.filaforms.app)  [ Try Demo ](https://filaforms.app/login) [ Get Started ](https://filaforms.app#pricing)

 [ Features ](https://filaforms.app#features) [ Pricing ](https://filaforms.app#pricing) [ Blog ](https://filaforms.app/blog) [ Documentation ](https://docs.filaforms.app) [ Try Demo ](https://filaforms.app/login) [ Get Started ](https://filaforms.app#pricing)

   ![FilaForms](https://filaforms.app/logo.svg) FilaForms

 IntegrationsNotion as a CRM for Form Submissions: A Laravel Workflow
========================================================

 filaforms.app/blog

  [    Back to blog ](https://filaforms.app/blog) [ Integrations ](https://filaforms.app/blog/category/integrations)

Notion as a CRM for Form Submissions: A Laravel Workflow
========================================================

 Manuk Minasyan ·  June 9, 2026  · 7 min read

 The question always lands on a Friday. Sales pings the channel: "Where are the demo signups from this week?" You point at the Filament admin. They point at a Notion database called *Pipeline*. Then somebody on the team — usually the founder, sometimes a junior dev — opens both windows and starts copy-pasting rows for thirty minutes.

I've watched two-person sales teams run their entire pipeline out of a Notion database while the Laravel app sitting six feet away from them owns the data. Notion is where they triage, assign owners, and write follow-up notes. The admin panel is where the data is *correct*. The bridge between the two is a Friday ritual nobody admits to. This post is about ending that ritual with around twenty lines of code, a Notion integration token, and a property mapping table that survives contact with reality. It is the Laravel-side recipe for `notion form integration laravel`, written by someone who got it wrong on the first pass.

How to send Laravel form submissions to a Notion database
---------------------------------------------------------

There are two paths and they look similar but cost different things. The first is direct: a `FormSubmitted` listener in your Laravel app that calls the Notion API and creates a database row. The second is middleware: route the submission to Zapier, Make, or n8n and let them call Notion for you. Both end at the same Notion page. They diverge on cost, control, and how you debug a failure at 11pm.

The direct path is twenty lines of PHP, free, and gives you the integration log in your own database. The middleware path is a five-minute drag-and-drop, costs per-task at volume, and the failure logs live in someone else's dashboard. If you own the Laravel app, the direct path wins. The rest of this post covers it.

Setting up a Notion integration and database
--------------------------------------------

Notion needs to know your Laravel app exists before it will accept a single API call. The setup is in three parts: create an internal integration, build the target database, then share the database with the integration.

Open [the Notion integrations page](https://www.notion.com/help/create-integrations-with-the-notion-api) and create a new internal integration named after your project. Pick the workspace, save, and copy the integration token — it starts with `secret_` or `ntn_`. Treat this like a password. It belongs in `.env`, not in the repo.

Next, build the database in Notion the way Sales wants to read it. Title property is *Email* or *Name* — pick one, you only get one. Add properties for the fields you care about: a `Source` select, a `Submitted at` date, an `Owner` person field, and whatever else maps from your form. Notion's title property is special: every database has exactly one, it's always required, and the API rejects a page without it.

Last step, and the one almost every Notion tutorial omits: open the database as a full page, click the connection menu (top right, three-dot), and add your integration. Without this step, every API call returns a `404` that reads like the database doesn't exist. It does. Notion just isn't telling your token about it yet.

Grab the database ID from the URL — it's the 32-character hex string between the last slash and the `?`. Drop it in config alongside the token.

Wiring it to FilaForms
----------------------

FilaForms fires a `FormSubmitted` event on every submission. The listener is short enough to read in one breath:

```
namespace App\Listeners;

use FilaForms\Core\Events\FormSubmitted;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Http;

class SyncSubmissionToNotion implements ShouldQueue
{
    public function handle(FormSubmitted $event): void
    {
        Http::withToken(config('services.notion.token'))
            ->withHeaders(['Notion-Version' => '2022-06-28'])
            ->post('https://api.notion.com/v1/pages', [
                'parent' => ['database_id' => config('services.notion.database_id')],
                'properties' => NotionSubmissionMapper::build($event->submission),
            ])
            ->throw();
    }
}

```

`ShouldQueue` is non-optional here, not a style choice. Notion's API has a real rate limit, and a synchronous call inside `FormSubmitted` would block the form response on a third-party HTTP round-trip. Put it on the queue, let the retry policy handle a transient `429`, and the form stays fast.

If you'd rather skip the listener entirely and let FilaForms POST the raw submission body to Notion via [the raw outgoing webhook path](/blog/webhooks-in-filaforms-send-submissions-anywhere), you can — but Notion's API does not accept raw form payloads. It expects a `pages.create` body with typed properties. The listener is where that translation lives. The `NotionSubmissionMapper` class is the next section.

Field mapping
-------------

Notion does not have one "value" type the way a SQL column does. It has fifteen-odd property types, each with a different shape, and the API rejects anything that doesn't match. The mapping is the part most tutorials skip and the part Sales cares about most, because filter and sort only work on properly typed properties.

FilaForms fieldNotion propertyNotesText (single line)`title` or `rich_text`One title per database; pick the field that identifies the row.Email`email`Plain string; the email type unlocks click-to-mail in Notion.Phone`phone_number`Plain string; no formatting enforced.Date`date`Must be ISO 8601 — `2026-06-09` or `2026-06-09T14:30:00Z`.Currency / Number`number`Strip currency symbols before sending; format lives on Notion's side.Select / Radio`select`The option must already exist in the database, or use `multi_select`.File upload`files`Needs a public URL. Notion does not host the file for you.A typed property is one filter Sales can use. A rich text dump is a string they have to read. The mapper is twenty lines but it earns every line.

Edge cases
----------

Three things will break this in production. Plan for them.

Notion's API rate-limits at an average of three requests per second. A burst of form submissions — a webinar landing page, say — will trip a `429`. The queue handles this for free if you give it sensible backoff; without the queue, you'd be writing retry logic by hand.

Partial failures are quieter and worse. Notion can create the page and reject a single property that failed validation — a malformed date, a select option that doesn't exist yet — and the API returns a `200` for the page with the bad property silently dropped. The fix is to validate property shapes in the mapper before the call, not after. The integration log surfaces the full request and response bodies so you can spot a property that's quietly going missing.

The token rotates. Notion lets you revoke and regenerate the integration secret at any time, and the day you do, every queued job blows up until the new token is in `.env`. Worth a runbook line.

What we got wrong
-----------------

The first version of our Notion sync wrote every field into a single rich text property called *Submission*. It worked. The API call succeeded. The page appeared in the database.

Sales used it for a week and went back to the spreadsheet. The reason was obvious in hindsight: a rich text dump cannot be filtered, sorted, or summed. They couldn't ask Notion "show me demo requests from this week" because the date was buried in a string. They couldn't sum estimated deal value because the number was buried in a string. They couldn't filter by source because every source was buried in the same string. Notion was being used as a Google Doc with extra steps.

We rebuilt the mapper to project each form field onto its own typed Notion property. The same data, dressed for filter and sort. Sales came back, and the Friday copy-paste ritual finally ended. The lesson, which applies past Notion: a CRM is its query surface. Schema is the product.

Try it
------

Notion is the durable record. [Slack handles the urgent ping](/blog/sending-form-submissions-to-slack-with-filaforms) — both can run off the same `FormSubmitted` event, and most teams want both. When the pipeline outgrows a Notion database (more than five people writing to it, real reporting, full sales motion), the move is graduating to HubSpot or a proper CRM. That's a later post in this series.

If you haven't set up FilaForms yet, you can [grab FilaForms here](https://filaforms.app). The listener pattern in this post sits on [FilaForms' outgoing webhooks](/blog/webhooks-in-filaforms-send-submissions-anywhere) — the same foundation every Connect-series integration uses.

 Related posts
-------------

 [  Integrations   May 26, 2026

 Sending Form Submissions to Slack with FilaForms
--------------------------------------------------

The sales team lives in Slack. Your form submissions live in a database. This post bridges the gap — and shows what we got wrong on the first version.

 ](https://filaforms.app/blog/sending-form-submissions-to-slack-with-filaforms) [  Integrations   May 19, 2026

 Webhooks in FilaForms: Send Submissions Anywhere
--------------------------------------------------

Laravel form webhooks are the universal escape hatch — one HTTP POST that lets a submission trigger anything downstream. Here's how FilaForms ships them reliably.

 ](https://filaforms.app/blog/webhooks-in-filaforms-send-submissions-anywhere) [  Integrations   Apr 27, 2026

 Sending Form Submissions to Google Sheets Automatically
---------------------------------------------------------

Your marketing person doesn't want to log into your admin panel. Your sales lead doesn't care about Filament. They want a spreadsheet. And honestly, that's

 ](https://filaforms.app/blog/sending-form-submissions-to-google-sheets-automatically)

    ![FilaForms Logo](/logo.svg) FilaForms

 Laravel form infrastructure for Filament. Stop rebuilding forms on every project.

 ### Product

 [ Features ](https://filaforms.app#features) [ Documentation ](https://docs.filaforms.app) [ Blog ](https://filaforms.app/blog) [ Pricing ](https://filaforms.app#pricing) [ Contact ](mailto:hello@filaforms.app)

 ### Legal

 [ Terms of Service ](https://filaforms.app/terms-of-service) [ Privacy Policy ](https://filaforms.app/privacy-policy)

  © 2025-2026 FilaForms. All rights reserved.

 [    ](mailto:hello@filaforms.app) [    ](https://x.com/MinasyanManuk)
