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
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.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.eventTimestamp, eventType, opportunityId, opportunityName.
Keeping deals up to date
Re-send a deal every time it changes, and includecrmLastModifiedAt.
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.crmAccountIdandcrmAccountDomain— 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 fromeventType, 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
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 IDcrmAccountId/crmAccountDomain— for account-level association
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.
Deduplication
Every event gets an ID. Send one yourself aseventId 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 onsent 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.