How to Integrate Salesforce Leads with a Notion Database
- Architect
- Jun 24
- 5 min read
Keeping lead data consistent and accessible across platforms is crucial for efficient sales and marketing workflows. While Salesforce remains the system of record for customer relationship management, Notion is rapidly gaining popularity as a flexible, collaborative workspace for teams.
This guide shows how to integrate Salesforce with Notion by enabling your Salesforce Leads to sync directly into a Notion database. Whether you're building a prototype, testing an internal workflow, or preparing for a production rollout, this tutorial will walk you through:
Creating a Notion database structured like Salesforce's Lead object
Authenticating and testing the Notion API
Sending lead data from Salesforce to Notion via Apex
Planning future improvements like duplicate prevention and bidirectional sync
By the end, you’ll have a working setup where lead records from Salesforce can be stored, viewed, and enriched inside a Notion database — combining the CRM power of Salesforce with Notion’s flexibility and UX.
Read More about the Notion Database: https://www.notion.com/help/category/databases
Notion API Reference: https://developers.notion.com/reference/intro
To Create New Data Base Rows: https://developers.notion.com/reference/post-page
Step 1: Creating a Notion database
Steps:
Go to Notion and create a new page.
Select Empty Database.
A new page will open with the default database view.
Go to Notion and create a new page:

Select Empty Database:

A new page will be opened with the default database view:

Rename the table to “Leads” and update the columns to match the Salesforce Lead object. Include the following fields:
First Name
Last Name
Company
Email
Phone
Your database should now look like this:

Step 2: Getting the Notion Access Token
Steps:
Open the Notion integrations page: Notion Integrations
Click "New Integration"
Enter the integration details (e.g., name, associated workspace)
Click "Configure Integration Settings"
Go to the Access tab
Click "Select Pages" and choose the Leads database
Click "Update Access"
Go back to the Configuration tab → Click "Show" next to Internal Integration Secret and copy the token
Open the Notion integration page: https://www.notion.so/profile/integrations
Click on the New integration:

Enter the integration details:

Click on the Configure integration settings:

Go to the access tab on the new page:

And click Select pages:

Select the Leads one and the Update access:

Then go back to the Configuration tab -> Click Show on the Internal Integration Secret and then copy the secret:

Test Connection in Postman:
You can test your integration using Postman by supplying the integration secret.
Endpoint: https://api.notion.com/v1/search
Authorization: Beare Token + the secret value
(on the screenshot I converted the secret into a variable
Headers:
Notion-Version : 2022-06-28
Content-Type: application/json
Body:
{
"filter": {
"property": "object",
"value": "database"
},
"page_size": 100
}



Test the integration by sending the request. If everything is fine, you will see a JSON response with the ID value:

Now, cpy the id value from the object "datbase" to use it for the future integration
Step 3: Send a New Lead from Salesforce to Notion
You can send leads to Notion using one of the following methods, depending on your team's preferred tools and level of automation:
Option 1: Apex Batch Job
Use an Apex class to send a selected batch of Lead records to Notion on a scheduled or manual basis.
Option 2: Lightning Web Component (LWC)
Build a custom LWC that allows users to manually push a single Lead record to Notion from the record page (e.g., via a “Sync to Notion” button).
Option 3: Salesforce Flow (No Code)
If you prefer a declarative, no-code approach, use Flow Builder to automate the sync process. Here's a high-level setup:
Prerequisites:
Create an Apex Action that wraps the HTTP POST request logic to Notion’s API
Mark the Apex method as @InvocableMethod to use it in Flow
Example Use Cases:
After Save Record-Triggered Flow: Automatically push a Lead to Notion after it’s created or updated
Screen Flow: Allow users to select fields and confirm sync before sending
Flow Configuration Steps:
In Setup → Flows, create a new Record-Triggered Flow on the Lead object
Add an Assignment step to format the input data if needed
Add an Action element and select your custom Apex action
Map the Flow inputs to the Apex method’s parameters (e.g., first name, email, database ID)
Test the Flow by creating or updating a Lead in Salesforce
This approach is ideal for admins who want automation without code, and it integrates smoothly with Salesforce’s native tools.
When using Apex or Flow, the JSON payload you send to Notion should follow this structure. Replace database_id with the actual ID of your Notion database:
{
"parent": {
"database_id": "21a***************f"
},
"properties": {
"Email": {
"email": "alice@example.com"
},
"Phone": {
"phone_number": "+14155552671"
},
"Company": {
"rich_text": [
{
"type": "text",
"text": {
"content": "Acme Corp",
"link": null
}
}
]
},
"Last Name": {
"rich_text": [
{
"type": "text",
"text": {
"content": "Doe",
"link": null
}
}
]
},
"First Name": {
"title": [
{
"type": "text",
"text": {
"content": "Alice",
"link": null
}
}
]
}
}
}
Here's a complete and clean Apex class with an @InvocableMethod that:
Accepts a recordId and databaseId as inputs from Flow
Queries the specified Lead
Builds a Notion-compatible JSON payload
Sends it to the Notion API via a Named Credential for security
Prerequisites:
Set up a Named Credential in Salesforce named Notion with:
Header: Authorization: Bearer <your_secret_token>
Notion-Version: 2022-06-28 added via a custom header or in the Apex call
Select “Per User” or “Named Principal” based on your needs
Apex Class:
public class NotionLeadSync {
public class NotionFlowInput {
@InvocableVariable(required=true)
public Id recordId;
@InvocableVariable(required=true)
public String databaseId;
}
@InvocableMethod(label='Send Lead to Notion')
public static void sendLeadsToNotion(List<NotionFlowInput> inputs) {
for (NotionFlowInput input : inputs) {
if (input.recordId == null || input.databaseId == null) continue;
Lead leadRecord = [SELECT FirstName, LastName, Company, Email, Phone FROM Lead WHERE Id = :input.recordId LIMIT 1];
Map<String, Object> payload = new Map<String, Object>{
'parent' => new Map<String, Object>{ 'database_id' => input.databaseId },
'properties' => new Map<String, Object>{
'First Name' => new Map<String, Object>{
'title' => new List<Object>{
new Map<String, Object>{
'text' => new Map<String, Object>{ 'content' => leadRecord.FirstName }
}
}
},
'Last Name' => new Map<String, Object>{
'rich_text' => new List<Object>{
new Map<String, Object>{
'text' => new Map<String, Object>{ 'content' => leadRecord.LastName }
}
}
},
'Company' => new Map<String, Object>{
'rich_text' => new List<Object>{
new Map<String, Object>{
'text' => new Map<String, Object>{ 'content' => leadRecord.Company }
}
}
},
'Email' => new Map<String, Object>{ 'email' => leadRecord.Email },
'Phone' => new Map<String, Object>{ 'phone_number' => leadRecord.Phone }
}
};
sendToNotion(JSON.serialize(payload));
}
}
private static void sendToNotion(String body) {
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('callout:Notion/v1/pages');
request.setMethod('POST');
request.setHeader('Content-Type', 'application/json');
request.setHeader('Notion-Version', '2022-06-28');
request.setBody(body);
HttpResponse response = http.send(request);
if (response.getStatusCode() >= 300) {
System.debug('Failed to sync with Notion: ' + response.getBody());
throw new CalloutException('Notion API call failed: ' + response.getStatus());
}
}
}
Future Enhancements
Add a Salesforce Lead ID to Notion to prevent duplicates
Store the Notion Page ID back in Salesforce for updates
Add error logging and sync status tracking
Expand to sync other Salesforce objects (e.g., Contacts, Accounts)
Integrate transcription or voice memo storage via Notion AI
Comments