Skip to main content
Octave connects directly to the common GTM tools. When your source isn’t one of them — an in-house system, a tool we don’t support yet, or an automation you built in n8n, Clay or Make — the generic events API takes the same four kinds of activity over plain HTTP. Events sent this way behave exactly like events from a native integration: they extract findings, match to your library, attach to deals, and feed outcomes.

Getting your webhook URL

In Octave, go to Settings → Integrations and find the section for the kind of event you want to send. At the bottom of each section is “Don’t see your provider? Send events directly via the Octave API.” — click Set up. The panel gives you your workspace API key and the webhook URL for that event type, already carrying the key.
The URL includes your API key as ?api_key=…. To send it as a header instead, drop the query string and pass api_key.

The four event types

Each type has its own endpoint. POST a JSON body matching the schema for that type — see the Log Event reference for every field.
Only sent and reply email events, and transcript call events, are processed for analytics. The rest are accepted and stored, but do not produce findings.

Email events

Required: eventTimestamp, eventType, subject, body, from, to.

Call events

Send the transcript as an array of speaker turns when you have them. It is faster and more accurate than a flat string, which Octave has to diarize with an LLM before it can attribute anything.
Required: eventTimestamp, eventType, title, transcript, participants.

CRM events

CRM events are different from the other three in one important way: a deal is one object that changes over time, not a one-off action. Read the Keeping deals up to date section below before you build against this endpoint.
Required: eventTimestamp, eventType, opportunityId, opportunityName.

Keeping deals up to date

Re-send a deal every time it changes, and include crmLastModifiedAt. Octave dedupes on a per-event ID. For emails and calls that is straightforward, because one send is one event. A deal is not: the same opportunityId comes back again and again as the amount moves, the stage advances and the close date slips. crmLastModifiedAt is what tells those pushes apart — without it, an updated deal can look identical to the one before it and be discarded as a duplicate, leaving your pipeline view frozen at the values it was first created with. If your system doesn’t expose a last-modified timestamp, Octave falls back to hashing the deal’s mutable fields, so genuine edits still land. Sending the timestamp is more reliable, and it is cheaper: the hash covers every field that can change, so a field Octave cannot see a timestamp for still counts as a new state. A last-modified timestamp that only moves on real edits keeps the event stream tighter than a hash that reacts to any field at all.
Sending the same deal repeatedly is expected and safe. Octave records a deal’s won, lost and created milestones once per opportunity, so re-sending a closed deal after an owner reassignment or a late-entered loss reason updates the deal record without adding a second “won” to your reporting.

Fields worth sending

These are optional, but each one measurably improves what Octave can do:
  • contactEmails — every contact on the deal, not just the primary. Event linking matches on all of them, so this is the single biggest lever on how many emails and calls attach to the opportunity.
  • crmAccountId and crmAccountDomain — matching on account name alone cannot separate two deals at companies with the same name, or the same company under two domains.
  • stageCategory — without it the stage bucket is inferred from eventType, so a deal deep in procurement still reads as simply “open”.
  • lossReason — powers win/loss analysis on closed-lost deals.
  • mergedOpportunityIds — when your system merges deals, list the ones merged into this deal. Octave folds their history in and tombstones them, so a merge doesn’t leave duplicates counting toward pipeline.

Social events

Required: eventTimestamp, eventType, body, from, to.

Connecting activity to deals

By default Octave works out which opportunity an email, call or social touch belongs to by matching participants and company domains inside a time window. That is a reasonable guess, and it is still a guess — it misses when the person on the thread isn’t on the deal, and it can attach to the wrong one when two deals share a domain. If you already know the deal, say so. Every email, call and social event accepts:
  • crmOpportunityId — your system’s deal ID
  • crmAccountId / crmAccountDomain — for account-level association
When crmOpportunityId matches a deal Octave knows about, the event is linked to it directly and the inference is skipped. An ID that doesn’t match anything falls back to the normal matching, so a stale ID never leaves an event unlinked.
Use the same IDs you send on your CRM events. They’re matched against the deals in your workspace, however those deals arrived — so this works even if your deals sync from HubSpot or Salesforce while your activity comes through this API.

Deduplication

Every event gets an ID. Send one yourself as eventId if you have a stable identifier — it is the most predictable option, and lets you re-send safely. If you don’t, Octave derives one from the event’s content. Re-sending identical content is treated as a duplicate and ignored; changed content is a new event.

Troubleshooting

Events accepted but nothing appears. Check the event type is one that gets processed. Emails produce findings on sent and reply, calls on transcript, and CRM on opportunity_created, deal_won, deal_lost and meeting_booked. Other event types are stored but do not feed extraction. A deal shows only one “won” despite several sends. That is deliberate. Each milestone is recorded once per opportunity, so later sends update the deal record without duplicating the milestone in reporting. Deal values look stale. You are almost certainly re-sending deals without crmLastModifiedAt. See Keeping deals up to date. Activity isn’t attaching to the right deal. Send crmOpportunityId on the email, call or social event rather than relying on participant matching. Nothing arrives at all. Confirm the API key in the URL matches the workspace you’re looking at, and that you’re POSTing to the endpoint for the right event type.