Webhooks
Table of Contents
Introduction
Snaily webhooks provide a powerful way to receive real-time notifications about events that occur in your Snaily workspace. Webhooks allow Snaily to push event data directly to your application as soon as something happens. This enables you to build responsive integrations, automate workflows, and keep your systems synchronized with your Snaily campaigns.
What are Webhooks?
Webhooks are HTTP callbacks that allow Snaily to notify your application when specific events occur. When you configure a webhook in Snaily, you provide a URL endpoint where you want to receive notifications. Snaily will automatically send HTTP POST requests to this endpoint whenever the subscribed events occur, containing all the relevant information about what happened.
Why Use Webhooks?
Webhooks solve several important problems in modern application integration:
- Real-time Updates: Get instant notifications when contacts connect, reply, or when invitations are sent.
- Automation: Trigger actions in your own systems automatically when events happen in Snaily. For example, update your CRM when a contact accepted your invitation or send a notification to your team when prospect replies.
- Integration: Easily connect Snaily with other tools and services in your tech stack, creating seamless workflows across platforms.
Getting Started
To start using Snaily webhooks, you need to:
- Set up an HTTP endpoint in your application that can receive POST requests
- Create a webhook configuration in Snaily with your endpoint URL
- Subscribe to the events you want to receive
- Handle incoming webhook payloads in your application
Creating a Webhook
You create and manage webhooks directly in the Snaily app interface.
Open the Snaily app, click your name in the top-right corner to open the account menu, then click Go to account. On the account page, use the left-hand navigation to select Webhooks (or open the Webhooks page directly), then click Add webhook, enter your endpoint URL, optionally configure a secret verification token, choose the events you want to receive, and save the configuration.
Webhook Events
Snaily webhooks are organized around events. When an event occurs, Snaily packages it into a webhook payload and sends it to webhook endpoints that are subscribed to that event type. All webhook payloads follow a consistent structure, making it easy to parse and handle different event types in your application.
Event Types
Snaily currently supports three webhook event types. Each event type represents a specific action or state change in your campaigns:
contact.connected Contact Connected
This event is triggered when a contact accepts your LinkedIn connection request within a campaign. It indicates that a potential lead has become a connected contact, opening the door for further communication.
When it fires: When a contact accepts your LinkedIn connection request that was sent as part of a campaign.
Use cases:
- Update your CRM when a new connection is established
- Trigger automated follow-up sequences
- Notify your sales team about new connections
- Track connection acceptance rates
contact.replied Contact Replied
This event is triggered when a contact sends a reply message in response to your campaign message or invitation. It’s a strong signal of engagement and interest.
When it fires: When a contact sends a message in a conversation that’s part of your campaign.
Use cases:
- Alert your team immediately when someone shows interest
- Route replies to the appropriate team member
- Update lead scoring systems based on engagement
- Trigger automated response workflows
- Log interactions in your CRM
invitation.sent Invitation Sent
This event is triggered when Snaily successfully sends a LinkedIn connection invitation to a contact as part of a campaign. It confirms that the invitation was dispatched.
When it fires: When a LinkedIn connection invitation is successfully sent to a contact in your campaign.
Use cases:
- Track invitation delivery rates
- Monitor campaign progress in real-time
- Update campaign analytics dashboards
- Trigger follow-up reminders
Payload Structure
All webhook payloads follow a consistent JSON structure. The payload contains an array of events, where each event includes metadata and the event-specific data.
Top-Level Structure
{
"events": [
{
"id": "unique-event-id",
"type": "contact.connected",
"created": "2026-02-19T10:30:00Z",
"processed": false,
"data": {
// Event-specific data (see below)
}
}
]
}
Event Object Fields
| Field | Type | Description |
|---|---|---|
id |
string | Unique identifier for this event. Use this for idempotency. |
type |
string | The event type: contact.connected, contact.replied, or invitation.sent |
created |
ISO 8601 datetime | Timestamp when the event occurred |
processed |
boolean | Whether the event has been processed (always false for new events) |
data |
object | Event-specific data (structure varies by event type) |
Common Data Fields
All event data objects include a user_context field that provides information about the Snaily user and workspace that generated the event:
{
"user_context": {
"snaily_email": "user@example.com",
"linkedin_profile_public_identifier": "john-doe",
"linkedin_profile_entity_id": "linkedin-entity-id-123"
}
}
Contact Connected Event Data
{
"id": "evt_123456",
"type": "contact.connected",
"created": "2026-02-19T10:30:00Z",
"processed": false,
"data": {
"created_at": "2026-02-19T10:30:00Z",
"contact": {
"snaily_id": "contact-id-123",
"given_name": "Jane",
"family_name": "Smith",
"full_name": "Jane Smith",
"occupation": "Senior Product Manager",
"location": "San Francisco, California, United States",
"country": "United States",
"distance": 2,
"linkedin_entity_id": "linkedin-entity-id",
"linkedin_public_identifier": "jane-smith",
"is_premium": true,
"last_action_at": "2026-02-19T09:15:00Z",
"email_address": "jane.smith@example.com",
"custom_field_1": "Custom value 1",
"custom_field_2": "Custom value 2",
"custom_field_3": "Custom value 3",
"last_job": {
"title": "Senior Product Manager",
"company": {
"name": "Tech Corp",
"website_url": "https://techcorp.com",
"industries": [{"id": "96", "name": "Technology, Information and Internet"}],
"employee_count_range": {"start": 1000, "end": 5000}
}
}
},
"campaign": {"id": "campaign-id-456", "name": "Q1 Outreach Campaign"},
"user_context": {
"snaily_email": "user@example.com",
"linkedin_profile_public_identifier": "john-doe",
"linkedin_profile_entity_id": "linkedin-entity-id-123"
}
}
}
Contact Replied Event Data
{
"id": "evt_789012",
"type": "contact.replied",
"created": "2026-02-19T11:45:00Z",
"processed": false,
"data": {
"created_at": "2026-02-19T11:45:00Z",
"reply_text": "Thank you for reaching out! I'd be happy to discuss potential opportunities.",
"contact": { /* Same contact structure as above */ },
"campaign": { /* Same campaign structure as above */ },
"user_context": { /* Same user context structure as above */ }
}
}
Invitation Sent Event Data
{
"id": "evt_345678",
"type": "invitation.sent",
"created": "2026-02-19T09:00:00Z",
"processed": false,
"data": {
"sent_at": "2026-02-19T09:00:00Z",
"contact": { /* Same contact structure as above */ },
"campaign": { /* Same campaign structure as above */ },
"user_context": { /* Same user context structure as above */ }
}
}
Contact Object Structure
| Field | Type | Description |
|---|---|---|
snaily_id |
string | Unique contact identifier |
given_name |
string | Contact’s first name |
family_name |
string | Contact’s last name |
full_name |
string | Contact’s full name |
occupation |
string | Current job title or occupation |
location |
string | Geographic location |
country |
string | Country name |
distance |
integer | Connection degree (1st, 2nd, 3rd) |
linkedin_entity_id |
string | LinkedIn internal entity ID |
linkedin_public_identifier |
string | LinkedIn public profile identifier |
is_premium |
boolean | Whether contact has LinkedIn Premium |
last_action_at |
ISO 8601 datetime | Timestamp of last LinkedIn activity |
email_address |
string | Email address (if available) |
custom_field_1 |
string | Custom field 1 |
custom_field_2 |
string | Custom field 2 |
custom_field_3 |
string | Custom field 3 |
last_job |
object | Most recent job position (see below) |
Job Position Object Structure
| Field | Type | Description |
|---|---|---|
title |
string | Job title |
company |
object | Company information (see below) |
Company Profile Object Structure
| Field | Type | Description |
|---|---|---|
name |
string | Company name |
website_url |
string | Company website URL |
industries |
array | List of industry objects with id and name |
employee_count_range |
object | Employee count range with start and end integers |
Campaign Object Structure
| Field | Type | Description |
|---|---|---|
id |
string | Unique campaign identifier |
name |
string | Campaign name |
Authentication
The secret token is optional. Snaily will send webhooks and work correctly even if you do not set a secret token. However, we recommend setting such a token so that you can verify that requests are coming from Snaily and reduce the risk of unauthorized or fake events reaching your endpoint.
When you create a webhook in the app, you can optionally provide a secret token. If provided, Snaily will send it in the X-Snaily-Token HTTP header with every webhook request to your endpoint.
Best Practices
1. Respond Quickly
Your webhook endpoint should respond with a 2xx status code as quickly as possible (ideally within a few seconds). Perform heavy processing asynchronously after responding. This prevents timeouts and ensures reliable delivery.
2. Handle Errors Gracefully
If your endpoint returns a non-2xx status code or times out, Snaily will retry the webhook delivery (see Troubleshooting → Failed Webhook Retries for the retry policy). Make sure your endpoint can handle retries gracefully and doesn’t perform duplicate actions.
4. Log Everything
Log all incoming webhook requests, including the payload and response status. This will help you debug issues and understand webhook delivery patterns.
5. Monitor Webhook Health
Set up monitoring and alerts for your webhook endpoints. Track response times, error rates, and delivery failures to ensure reliable operation.
Troubleshooting
Webhook Not Receiving Events
- Verify that your webhook is enabled in Snaily
- Check that you’ve subscribed to the correct event types
- Ensure your endpoint URL is accessible and returns 2xx status codes
- Check your server logs for incoming requests
- Verify that your firewall allows incoming connections from Snaily’s servers
Authentication Failures
- Verify that the
X-Snaily-Tokenheader matches what you configured - Check that your webhook handler is reading the
X-Snaily-Tokenheader - Ensure there are no extra spaces or characters in the secret token
Timeout Errors
- Respond to webhook requests quickly (within a few seconds)
- Move heavy processing to background jobs
- Increase your server’s timeout settings if necessary
Failed Webhook Retries
How Snaily retries failed deliveries
When a webhook cannot be delivered (non-2xx response or timeout), Snaily does not give up immediately:
- We schedule 14 more delivery attempts, with 12 hours between each attempt.
- If after these 14 retries the webhook still fails, the event is removed and will not be sent again.
If your endpoint keeps failing, verify:
- Server availability and uptime
- Network connectivity
- SSL certificate validity (for HTTPS endpoints)
- Error logs for specific failure reasons
Conclusion
Snaily webhooks provide a powerful and efficient way to integrate your applications with Snaily’s campaign management platform. By following this documentation and implementing webhooks correctly, you can build real-time integrations that keep your systems synchronized and automate your workflows.
For additional support or questions, please refer to the Snaily documentation or contact our support team.
