curl --request POST \
--url https://app.octavehq.com/api/v2/analytics/webhook/receive/generic/{eventType} \
--header 'Content-Type: application/json' \
--header 'api_key: <api-key>' \
--data '
{
"eventTimestamp": "2024-02-03T10:30:00Z",
"eventType": "sent",
"subject": "Follow up on our conversation",
"body": {
"text": "Hi John, Just wanted to follow up on our call yesterday...",
"html": "<p>Hi John,</p><p>Just wanted to follow up on our call yesterday...</p>"
},
"from": {
"email": "sarah@company.com",
"name": "Sarah Johnson"
},
"to": [
{
"email": "john@prospect.com",
"name": "John Smith"
}
],
"conversationId": "conv_abc123",
"campaignId": "campaign_xyz"
}
'{
"_metadata": {
"requestId": "requestId",
"timestamp": "2021-01-01T00:00:00.000Z",
"usage": 0,
"message": "message"
},
"received": true,
"connection": {
"providerName": "INSTANTLY",
"shouldProcess": true,
"connectionMethod": "WEBHOOK"
},
"additionalData": {},
"validationErrors": {
"fieldErrors": {},
"formErrors": [
"<string>"
]
}
}{
"_metadata": {
"requestId": "requestId",
"timestamp": "2021-01-01T00:00:00.000Z",
"usage": 0,
"message": "message"
},
"message": "<string>"
}{
"_metadata": {
"requestId": "requestId",
"timestamp": "2021-01-01T00:00:00.000Z",
"usage": 0,
"message": "message"
},
"message": "<string>"
}Log Event
Log a custom event — emails, calls, CRM, and social data from your own integrations (n8n, Clay, Make, etc.) — into the analytics pipeline. One event per request; to load history in batches of up to 1000 use POST /event/import, which takes the same event shapes plus a type discriminator.
Event Types
The {eventType} path parameter determines the expected payload schema. Each event type has its own set of supported sub-types; the schema for each is listed under Body below, with a description per field.
emails — Email Events
Supported eventType values: sent, reply, opened, clicked, bounced, unsubscribed
- Only
sentandreplyare processed for analytics; others are ingested but not processed. - Required fields:
eventTimestamp,eventType,subject,body(text or html),from,to - Optional:
cc,bcc,eventId,messageId,conversationId,campaignId,crmOpportunityId,crmAccountId,crmAccountDomain,sourceProviderName,octaveRequestId,customMetadata
calls — Call/Meeting Events
Supported eventType values: transcript, scheduled, completed, missed
- Only
transcriptis processed for analytics; others are ingested but not processed. - Required fields:
eventTimestamp,eventType,title,transcript,participants - Optional:
duration,recordingUrl,meetingPlatform,eventId,conversationId,crmOpportunityId,crmAccountId,crmAccountDomain,sourceProviderName,customMetadata - Transcript formats: Can be a flat string (LLM will diarize into speaker turns) or a structured array of entries with speaker attribution (recommended — faster and more reliable).
crm — CRM Events
Supported eventType values: opportunity_created, deal_won, deal_lost, meeting_booked
- All CRM event types are processed for analytics.
- Required fields:
eventTimestamp,eventType,opportunityId,opportunityName - Optional:
amount,currency,stage,stageCategory,crmPipelineId,crmPipelineName,accountName,crmAccountId,crmAccountDomain,contactEmail,contactName,contactEmails,ownerName,ownerEmail,crmOwnerId,closeDate,createdDate,crmLastModifiedAt,lossReason,mergedOpportunityIds,eventId,sourceProviderName,customMetadata - A deal is one object that changes over time: re-send it whenever it changes and include
crmLastModifiedAtso the new state is not discarded as a duplicate of the previous push.
social — Social/LinkedIn Events
Supported eventType values: connection_sent, connection_accepted, message_sent, message_received
- All social event types are processed for analytics.
- Required fields:
eventTimestamp,eventType,body(text or html),from,to - Optional:
subject,eventId,conversationId,campaignId,messageType,campaignName,crmOpportunityId,crmAccountId,crmAccountDomain,sourceProviderName,octaveRequestId,customMetadata
Linking to deals
Email, call and social events accept crmOpportunityId / crmAccountId / crmAccountDomain. When crmOpportunityId matches a deal in the workspace the event is attached to it directly and participant/domain inference is skipped; an unknown ID falls back to inference. Use the same IDs you send on your CRM events.
Deduplication
You can provide an optional eventId field for explicit deduplication. If not provided, an ID is auto-generated from the event content:
- Emails:
from_email + subject + timestamp + first_to_email - Calls:
title + timestamp + first_participant + first_100_chars_transcript - CRM:
opportunityId + eventType + crmLastModifiedAt— or, whencrmLastModifiedAtis absent, a hash of the deal’s mutable fields, so a genuinely changed deal is a new event and an unchanged re-send is a duplicate - Social:
from_email + eventType + timestamp + first_to_email
Response
A payload that fails schema validation is answered with HTTP 200 and received: false, with the per-field messages in validationErrors — check received, not just the status code. The request body is limited to 10 MB.
Authentication
Workspace is identified by API key, passed as an api_key header or, on this endpoint only, as the api_key query parameter.
curl --request POST \
--url https://app.octavehq.com/api/v2/analytics/webhook/receive/generic/{eventType} \
--header 'Content-Type: application/json' \
--header 'api_key: <api-key>' \
--data '
{
"eventTimestamp": "2024-02-03T10:30:00Z",
"eventType": "sent",
"subject": "Follow up on our conversation",
"body": {
"text": "Hi John, Just wanted to follow up on our call yesterday...",
"html": "<p>Hi John,</p><p>Just wanted to follow up on our call yesterday...</p>"
},
"from": {
"email": "sarah@company.com",
"name": "Sarah Johnson"
},
"to": [
{
"email": "john@prospect.com",
"name": "John Smith"
}
],
"conversationId": "conv_abc123",
"campaignId": "campaign_xyz"
}
'{
"_metadata": {
"requestId": "requestId",
"timestamp": "2021-01-01T00:00:00.000Z",
"usage": 0,
"message": "message"
},
"received": true,
"connection": {
"providerName": "INSTANTLY",
"shouldProcess": true,
"connectionMethod": "WEBHOOK"
},
"additionalData": {},
"validationErrors": {
"fieldErrors": {},
"formErrors": [
"<string>"
]
}
}{
"_metadata": {
"requestId": "requestId",
"timestamp": "2021-01-01T00:00:00.000Z",
"usage": 0,
"message": "message"
},
"message": "<string>"
}{
"_metadata": {
"requestId": "requestId",
"timestamp": "2021-01-01T00:00:00.000Z",
"usage": 0,
"message": "message"
},
"message": "<string>"
}Authorizations
Path Parameters
Type of event being sent
emails, calls, crm, social "emails"
Query Parameters
Provide api key if not in header
Body
- Email Event
- Call Event
- CRM Event
- Social Event
- Email Event
- Call Event
- CRM Event
- Social Event
- Email Event
- Call Event
- CRM Event
- Social Event
- Email Event
- Call Event
- CRM Event
- Social Event
Webhook payload. The schema depends on the {eventType} path parameter:
emails— Email Event schemacalls— Call Event schemacrm— CRM Event schemasocial— Social Event schema (LinkedIn/social outreach)
Timestamp of the event. Accepts an ISO 8601 string (e.g., "2024-02-03T10:30:00Z"), a Unix epoch in milliseconds (>= 1e12), or a Unix epoch in seconds. Must resolve to a date within 50 years past or 5 years future.
"2024-02-03T10:30:00Z"
Type of email event. Only 'sent' and 'reply' are processed for analytics; others are ingested but not processed.
sent, reply, opened, clicked, bounced, unsubscribed Email subject line
"Follow up on our conversation"
Email body. At least one of text or html must be provided.
Show child attributes
Show child attributes
Sender
Show child attributes
Show child attributes
Recipients (at least one required)
1Show child attributes
Show child attributes
CC recipients
Show child attributes
Show child attributes
BCC recipients
Show child attributes
Show child attributes
Explicit event ID for deduplication. If not provided, auto-generated from: from_email + subject + timestamp + first_to_email
"deal-001-email-sent-1"
The message's own identifier as the mail system assigned it (the RFC 5322 Message-ID). Lets Octave recognise the same email when it also arrives from another source, such as a CRM's logged copy. Max 255 characters.
255"<CAF1b2c3d4@mail.gmail.com>"
Conversation/thread ID for grouping related emails
Campaign ID for grouping campaign emails
Octave request ID for tracking
Display override for the activity feed. Case-insensitive match against a supported provider name; when set, that provider's logo is shown instead of the generic Octave icon.
Your system's deal ID. Links this event straight to that opportunity instead of Octave inferring the deal from participants and timing — which misses when the participant is not on the deal, and mis-fires when two deals share a domain.
"opp_12345"
Your system's account/company ID. Names the account without naming a deal: Octave narrows its deal inference to that account's opportunities, so the event lands on the right deal even when none of its participants are on it.
"acct_67890"
The account's domain (e.g. acme.com). Same effect as crmAccountId, keyed by domain — use it when your source knows the company but not its CRM ID.
"acme.com"
Arbitrary key-value metadata
Show child attributes
Show child attributes
Response
Webhook received successfully
Show child attributes
Show child attributes
Whether the payload was received
Connection details
Show child attributes
Show child attributes
Additional data about the processed event
Show child attributes
Show child attributes
Per-field validation errors when the payload fails schema validation. Mirrors Zod's flatten() output so callers can map errors back to the offending fields.
Show child attributes
Show child attributes