Overview
What you’ll build
A bidirectional integration enabling:
- Automatic recording-to-opportunity matching
- CRM context in Siro (customer names, deal amounts, outcomes)
- Entity extraction data flowing back to your CRM
Time estimate
4-8 hours for a developer familiar with REST APIs
Prerequisites
- API development experience
- Admin access to your Siro workspace
- Your system exposes appointment/opportunity data via API or database
Step 1: Get Your Siro API Credentials
Generate Your API Key
- Log into your Siro workspace as an admin
- Navigate to Person Icon → API Tokens
- Click Generate New API Token
- Store this securely - you’ll use it in all API requests
API Base URL
Most API calls use:
https://functions.siro.ai/api-externalApi/v1
Authentication: Include your API key in the header:
curl --request GET \
--url 'https://functions.siro.ai/api-externalApi/v1/core/mobile-events?pageSize=100' \
--header 'Authorization: Bearer <token>'
Documentation: Full API reference at docs.siro.ai
Step 2: Understand the Basics of the Data Model
Siro’s integration data model maps to standard CRM concepts:
| Your System | Siro Equivalent | Purpose |
|---|
| Sales Rep / User in your CRM | User | Link reps in CRM to reps in Siro |
| Customer / Account | Account | Customer information |
| Opportunity / Deal / Lead | Opportunity | Sales outcomes with dollar values |
| Appointment / Meeting | Engagement | Scheduled interactions that get recorded |
| Recording | Recordings | Siro recording |
Key Relationship
The critical link is: Recording ↔ Engagement ↔ Opportunity AND/OR Account
When you sync an Engagement to Siro with appointment details (time, location, rep), Siro can automatically match recordings to that engagement and surface the linked Opportunity context.
Step 3: Sync Your Data to Siro
3.1 Link CRM Users to Siro Users
User linking happens automatically. When you sync engagements or opportunities, include your CRM’s user identifier with externalId, email, and name. Siro automatically maps to existing workspace users by email or name match. Manual override available in Settings → Integrations → User Mapping.
3.2 Sync Appointments (Engagements)
This is the core of the integration. Syncing engagements enables appointment lists for reps, automatic recording linking, and CRM context for AI features.
Endpoint: PUT /v1/integrations/sync/engagements • Full docs
Example request:
curl --request PUT \
--url 'https://functions.siro.ai/api-externalApi/v1/integrations/sync/engagements' \
--header 'Authorization: Bearer YOUR_API_TOKEN' \
--header 'Content-Type: application/json' \
--data '@-' <<EOF
{
"externalId": "appt-456",
"startTime": "2026-02-15T14:00:00Z",
"endTime": "2026-02-15T15:00:00Z",
"subject": "Smith Kitchen Remodel Consultation",
"engagementType": {
"activityType": "MEETING",
"name": "meeting"
},
"engagementUsers": [
{
"externalId": "rep-123-from-your-crm",
"email": "rep-123@kitchenremodel.com",
"name": "John Sales"
}
],
"account": {
"externalId": "account-789"
},
"opportunity": {
"externalId": "opp-101"
}
}
EOF
Payload notes:
activityType: Valid values are MEETING, CALL, APPOINTMENT, EMAIL, TEXT, EVENT
- Only MEETING, APPOINTMENT, and EVENT appear in the Appointment List feature
3.3 Sync Opportunities
Adds deal context (amount, disposition, customer name) to recordings.
Endpoint: PUT /v1/integrations/sync/opportunities • Full docs
Example request:
curl --request PUT \
--url 'https://functions.siro.ai/api-externalApi/v1/integrations/sync/opportunities' \
--header 'Authorization: Bearer YOUR_API_TOKEN' \
--header 'Content-Type: application/json' \
--data '@-' <<EOF
{
"externalId": "opp-101",
"name": "Smith Kitchen Remodel",
"amount": 45000,
"closedAt": "2026-03-01T00:00:00Z",
"disposition": "WON",
"account": {
"externalId": "account-789"
},
"opportunityUsers": [
{
"externalId": "rep-123-from-your-crm",
"email": "rep-123@kitchenremodel.com",
"name": "John Sales"
}
]
}
EOF
3.4 Sync Accounts
Adds customer context (name, address, contact info) to recordings. Account syncing happens automatically when you include the nested account object with an externalId in engagement or opportunity payloads. See the engagement example in 3.2 for the basic structure, or add optional fields like emailAddresses, phoneNumbers, and addresses as needed.
Step 4: Pull Data from Siro Back to Your System
Once recordings are created and linked, retrieve AI-generated insights. Siro supports two ways to receive this data:
- Real-time webhooks (recommended) — subscribe to events on your Siro workspace and receive HTTP callbacks the moment a recording is processed and linked to a CRM engagement. Covered in sections 4.1–4.3 below.
- Polling — periodically query the engagement endpoint to check for linked recordings, then pull enriched data from separate endpoints. See Alternative: Polling Flow.
Note: Most endpoints use your organization API token. Get Recording Details (section 4.3) and Get Entity Extractions (section 4.5) require OAuth authentication. Skip OAuth setup if you only need the polling flow for engagements and summaries.
1. Create an OAuth App
Endpoint: POST /v1/core/oauth/apps • Full docs
Provide appName, owner (user-id), and organizationId. Store the returned clientID and clientSecret securely.
2. Generate OAuth Access Tokens
Endpoint: POST /v1/core/oauth/apps/{clientId}/access-token • Full docs
Provide clientSecret, userId, and scope: "read". Use the returned accessToken for entity extractions. Tokens expire after 16 hours.
4.1 Subscribe to Webhook Events
Siro emits two event types that together signal a recording is fully ready for downstream processing:
| Event type | Fires when |
|---|
integrations.recordingProcessed | Siro finishes processing the recording (transcript, summary, entity extraction, etc.) |
integrations.recordingLinked | Siro recording is definitively linked to a CRM record |
These events fire independently and may arrive in either order — the recording may be linked before processing finishes, or vice versa.
How to subscribe:
Webhook subscriptions are managed from the Webhooks page in the Siro dashboard.
- As an org admin, open the Organization Admin Area from the top-right menu and select Webhooks. You’ll see the Endpoints list where all your configured webhooks are shown.
- Click + Add Endpoint. Fill in your Endpoint URL (the HTTPS URL where you want to receive events), an optional Description, and select the events to subscribe to. Check both integrations.recordingLinked and integrations.recordingProcessed.
- After saving, you’ll see the endpoint detail page with your Signing Secret. Copy this secret — you’ll use it to verify that incoming webhook payloads are authentic.
You can test your endpoint before going live using the Testing tab on the
endpoint detail page, or by using Webhook.site to
inspect payloads without setting up a server.
Verifying webhook signatures
Every webhook delivery includes three headers used for verification:
| Header | Description |
|---|
svix-id | Unique message identifier |
svix-timestamp | Timestamp in seconds since epoch |
svix-signature | Base64-encoded signature(s), e.g. v1,<sig> |
The recommended approach is to use the official Svix library, which handles signature construction and timestamp tolerance for you.
import { Webhook } from "svix"; // npm install svix
const secret = "whsec_YOUR_SIGNING_SECRET";
export default async function handler(req, res) {
const payload = (await buffer(req)).toString(); // raw body
const headers = req.headers;
const wh = new Webhook(secret);
try {
wh.verify(payload, headers);
} catch (err) {
return res.status(400).json({});
}
// Signature valid — process the event
res.json({});
}
You must use the raw request body when verifying. Parsing the JSON first and re-serializing it will break the signature.
Subscribe to both event types. Every delivery carries the current state of both flags regardless of which event triggered it, which is what makes the filtering rule in 4.2 work without any correlation logic on your side.
4.2 Handle Webhook Payloads
Both event types share the same payload shape:
{
"recordingId": "rec-abc-def",
"siroUserId": "siro-user-123",
"recordingProcessed": true,
"recordingLinked": true,
"eventType": "integrations.recordingProcessed",
"crm": {
"integrationConnectionId": "conn-123",
"users": [{ "id": "user-uuid", "externalId": "crm-user-123" }],
"engagement": { "id": "eng-uuid", "externalId": "appt-456" },
"opportunity": { "id": "opp-uuid", "externalId": "opp-101" },
"account": { "id": "acct-uuid", "externalId": "account-789" }
}
}
Key fields:
recordingProcessed / recordingLinked — current boolean state of each condition. Every payload reports both, regardless of which event was emitted.
crm.engagement.externalId — the appointment ID you originally synced (from 3.2).
crm.opportunity.externalId — the opportunity ID you originally synced (from 3.3).
Filtering rule: act only when both recordingProcessed and recordingLinked are true.
Because every delivery reports current state for both conditions, the handler for whichever event fires last will naturally observe true / true — no correlation or state machine is needed.
Example handler:
async function onSiroWebhook(payload) {
if (!payload.recordingProcessed || !payload.recordingLinked) {
// Not ready yet — the other event will arrive.
return;
}
const { recordingId, crm } = payload;
const engagementExternalId = crm?.engagement?.externalId;
const opportunityExternalId = crm?.opportunity?.externalId;
// Fetch enriched data — see 4.3
const recording = await fetchRecordingDetails(recordingId);
await yourCrm.attach({
engagementExternalId,
opportunityExternalId,
summary: recording.summary,
extractions: recording.entityExtractions,
});
}
Idempotency: because the “both true” condition can be observed twice (once per event), dedupe by recordingId if your downstream side-effects aren’t idempotent.
Endpoint: GET /v1/core/recordings/{recordingId}
Base URL: https://api.siro.ai
Note: This base URL is different from the main external API (https://functions.siro.ai/api-externalApi/v1). It matches the base used by the Entity Extractions endpoint (4.5).
Authentication: Use OAuth access token (header: x-siro-auth-token) — see the OAuth Setup section above.
Query parameters:
| Param | Type | Purpose |
|---|
showSummary | boolean | Include the concatenated LLM summary in the response |
showEntityExtractions | boolean | Include per-definition entity extractions with CRM mappings |
Both default to false.
Example request:
curl --request GET \
--url 'https://api.siro.ai/v1/core/recordings/rec-abc-def?showSummary=true&showEntityExtractions=true' \
--header 'x-siro-auth-token: YOUR_OAUTH_ACCESS_TOKEN'
Response (relevant fields):
{
"data": {
"id": "rec-abc-def",
"organizationId": "org-789",
"userId": "user-123",
"summary": "Overview:\nThe rep walked the customer through financing options.\n\nNext Steps:\nSend a written proposal by Friday.",
"entityExtractions": [
{
"id": "extraction_001",
"recordingId": "rec-abc-def",
"siroEntityDefinitionId": "def-uuid",
"siroEntityDefinitionName": "Budget",
"status": "SUCCESS",
"extraction": [
{
"name": "Budget",
"value": "$40,000 - $50,000",
"mappings": [
{ "crmModelName": "Opportunity", "crmFieldName": "Budget__c" }
]
}
]
}
]
}
}
Use case: in a single round-trip, pull both the conversation summary and any extracted custom fields ready to write back to your CRM.
Alternative: Polling Flow
If webhooks aren’t an option for your environment, use the engagement endpoint to poll for linked recordings and pull enriched data from the endpoints below. This flow uses an org API token for everything except entity extractions (4.5), which still requires OAuth.
4.4 Get Linked Recording for an Engagement
Endpoint: GET /v1/integrations/engagements/{id} • Full docs
Response includes:
{
"id": "eng-123",
"externalId": "appt-456",
"recordingId": "rec-abc-def",
"engagementType": "appointment",
"opportunityId": "opp-101",
"accountId": "account-789"
}
Use the recordingId to fetch detailed data.
Endpoint: GET /v1/core/entities/extractions/{recordingId} • Full docs
Base URL: https://api.siro.ai
Note: This base URL is different from other API endpoints.
Authentication: Use OAuth access token (header: x-siro-auth-token)
Response example:
{
"data": [
{
"id": "extraction_001",
"recordingId": "rec-abc-def",
"extraction": [
{
"name": "Budget",
"value": "$40,000 - $50,000"
},
{
"name": "Timeline",
"value": "Spring 2026"
},
{
"name": "Decision Maker",
"value": "Both homeowners present, wife is primary"
},
{
"name": "Objections",
"value": "Concerned about project timeline due to summer vacation plans"
}
],
"createdAt": "2026-01-28T00:00:00Z",
"updatedAt": "2026-01-28T00:00:00Z"
}
]
}
Use case: Write extracted fields back to your CRM to auto-populate data from conversations.
4.6 Get Recording Summaries
Endpoint: GET /v1/core/recordings/{recordingId}/summaries
Response:
{
"data": [
{
"id": "summary-001",
"name": "AI Summary",
"content": "Summary text here..."
}
]
}
Use case: Write summaries as CRM notes to create an activity trail.
Auto Start/Stop via Deep Linking (Optional)
Start Siro recordings directly from your mobile app:
URL format:
siro://record?appointmentId={external-id}&title={customer-name}&opportunityId={opp-external-id}
Example:
siro://record?appointmentId=appt-456&title=Smith Kitchen Remodel&opportunityId=opp-101
Siro will use the appointmentId to link the recording to the engagement and opportunityId to link the associated opportunity immediately.
Next Steps
- Test it: Sync a test appointment, record a conversation at that time, and verify CRM context appears
- Automate syncs: Use real-time webhooks (recommended) or batch jobs every 10 minutes
- Custom fields: Work with your CSM to configure custom entity extraction fields
- Troubleshoot: If recordings aren’t linking, check Settings → Users to verify email mappings
- Train your team: Show reps how recordings link to CRM records
Getting Help
Technical questions: Email your Customer Success Manager or reach out to customersuccess@siro.ai
API issues: Include your request details (method, endpoint, payload) and organization ID when reaching out.