Skip to main content

API - Webhooks

Surfe Webhooks: Real-Time Notifications Made Simple

What is a webhook?

Think of a webhook as a "special messenger" that automatically sends you data the moment something important happens. So you don’t have to keep checking manually. It’s like a notifier that does the worrying for you.


How Does It Work? Three Simple Steps

  1. You give us a URL This is like giving us an address where we can send a message. It's called your webhook endpoint — a public URL that can accept a message (a POST request) from us.

  2. An event happens For example, Surfe might finish enriching a contact. When that's done, we automatically send the info to your URL, no polling required.

  3. You say "Got it!" Your server needs to reply with a 200 OK — that's your way of saying, "Thanks, I received the data." If you send something else, we might try sending it again based on your settings.

Your webhook URL must use HTTPS. HTTP URLs are not accepted and will be rejected by Surfe. Make sure your endpoint starts with https:// before adding it to your request.
​

What Event Can I Get Notified About?

Right now, Surfe supports two events:

person.enrichment.completed — This tells you when a contact's enrichment is done. It includes useful information like their name, email, job title, and more.

When this event happens and you provided a webhookUrl, Surfe sends:
​

{
"eventType": "person.enrichment.completed",
"data": {
"enrichmentID": "0198c820-d5f1-7c7f-a9f7-a19fc24846t7",
"person": {
"externalID": "Webhooktest-id",
"firstName": "David",
"lastName": "Chevalier",
"companyName": "Surfe",
"companyDomain": "surfe.com",
"linkedInUrl": "https://linkedin.com/in/david-maurice-chevalier",
"jobTitle": "Co-Founder & CEO",
"location": "Paris, Île-de-France",
"country": "France",
"emails": [
{
"email": "d.c@surfe.com",
"validationStatus": "VALID"
}
],
"mobilePhones": [
{
"mobilePhone": "+491111113211",
"confidenceScore": 0.95
}
],
"status": "COMPLETED"
}
}
}

This structure gives you everything you need to process the enriched data — no polling needed.

company.enrichment.completed — Get notified when Surfe finishes enriching details about a company, like their name, website, size, industry, and more.

When this event happens and you provided a webhookUrl, Surfe sends:
​

{
 "companies": [
   {
     "description": "Sales teams waste too much time on repetitive admin tasks. Surfe handles everything before the phone call - identifying target accounts, building lead lists, and enriching data. Our mission is to empower sales teams, automating the essential steps of the workflow while enhancing the human touch. Trusted by 3,000+ companies from local to global GTM needs like Google, Uber, AWS, Bolt, Pigment. Compatible with HubSpot, Salesforce, Pipedrive, and Copper CRM. As a GDPR-compliant and ISO27001-certified tool, Surfe helps your team operate from a gold standard of data, making sure everything is structured, categorized, updated, and protected. Surfe has been selected as Top 100 fastest-growing products on G2 and recognized as a Top 100 Rising European Startups by VivaTech in 2025.",
     "digitalPresence": [
       {
         "name": "LinkedIn",
         "url": "https://www.linkedin.com/company/surfe"
       }
     ],
     "employeeCount": 65,
     "externalID": "external-id",
     "followersCountLinkedin": 8896,
     "founded": "2020",
     "fundingRounds": [
       {
         "amount": 9999999999,
         "amountCurrency": "$",
         "announcedDate": "2021-01-01",
         "leadInvestors": [
           "Investor A",
           "Investor B"
         ],
         "name": "Seed Round - Surfe"
       }
     ],
     "hqAddress": "52 Rue Chaussée D'antin Paris FR 75009",
     "hqCountry": "FR",
     "industry": "IT Services",
     "ipo": {
       "date": "2021-01-01",
       "sharePrice": 100,
       "sharePriceCurrency": "$"
     },
     "isPublic": false,
     "keywords": [
       "crm updates",
       "reply rate",
       "linkedin sales",
       "linkedin messages",
       "synchronize linkedin",
       "secure crm"
     ],
     "linkedInURL": "https://linkedin.com/company/surfe",
     "name": "Surfe",
     "parentOrganization": {
       "name": "Parent Organization",
       "website": "https://www.parentorganization.com"
     },
     "phones": [
       ""
     ],
     "revenue": "10-50M",
     "signals": {
       "leadershipChange": {
         "changeCount": 23,
         "changes": [
           {
             "date": "2026-07-01",
             "firstName": "Jane",
             "lastName": "Doe",
             "linkedinUrl": "https://www.linkedin.com/in/janedoe",
             "newCompanyDomain": "surfe.com",
             "newTitle": "VP Sales",
             "oldCompanyDomain": "starindustries.com",
             "oldTitle": "Sales Manager",
             "type": "promotion"
           }
         ]
       }
     },
     "status": "COMPLETED",
     "stocks": [
       {
         "exchange": "string",
         "ticker": "string"
       }
     ],
     "subIndustry": "Internet Services & Infrastructure",
     "websites": [
       "surfe.com"
     ]
   }
 ],
 "percentCompleted": 50,
 "status": "IN_PROGRESS"
}

signals.leadershipChange is null when no leadership change data is available for the company. The changes array includes the most recent leadership changes.

 

batch.enrichment.completed — Triggered when all enrichments in a batch have finished.

 

Example payload:

 

{
"eventType": "batch.enrichment.completed",
"data": {
"batchID": "your-batch-id",
"enrichmentID": "your-enrichment-id",
"enrichmentCallbackURL": "https://api.surfe.com/v2/people/enrich/your-enrichment-id",
"message": "Your enrichment has completed"
}
}

 

Why Use Webhooks Instead of Polling?

  • Automatic: No manual checking. You get updates right away.

  • Efficient: Your system isn't kept busy asking for info over and over again.

  • Light on resources: Saves you time and computing power.

How to Set It Up in Plain English

  1. When you send your enrichment request, include a webhookUrl inside notificationOptions.

  2. Make sure your server can accept POST requests and respond quickly with 200 OK.

  3. Handle the data when it arrives — maybe store it, process it, or trigger another action.

Setting up a people enrichment webhook:

 

curl -X POST "https://api.surfe.com/v2/people/enrich" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json" \
-d '{
"include": {
"email": true,
"linkedInUrl": false,
"mobile": false
},
"notificationOptions": {
"webhookUrl": "https://your-server.com/webhook"
},
"people": [
{
"companyDomain": "surfe.com",
"companyName": "Surfe",
"externalID": "external-id",
"firstName": "David",
"lastName": "Chevalier",
"linkedinUrl": "https://www.linkedin.com/in/david-maurice-chevalier"
}
]
}'

Once the enrichment is done, you'll receive the person.enrichment.completed payload at your webhook endpoint.
​

Setting up a company enrichment webhook:

 

curl -X POST "https://api.surfe.com/v2/companies/enrich" \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json" \
-d '{
"companies": [
{
"domain": "surfe.com",
"externalID": "your-internal-id"
}
],
"notificationOptions": {
"webhookUrl": "https://your-server.com/webhook"
}
}'

Once complete, you'll receive the company.enrichment.completed payload at your webhook endpoint.
​
​Summary Table

When You Do This…

Then This Happens…

Provide a webhookUrl

Surfe sends updates automatically when enrichment completes

Your server returns 200 OK

Surfe knows you’ve received the data successfully

You receive the payload in your system

You can then use or store the enriched information


To verify that webhook requests are genuinely from Surfe, see our guide on Webhooks: Verifying Webhook Signatures
​

​
Need Help?

If you have any questions or need further assistance, feel free to reach out to our support team.
​

Additional Resources

Was this article helpful?

0 out of 0 found this helpful
Have more questions? Submit a request
Return to top

Comments

0 comments

Please sign in to leave a comment.