Documentation Index
Fetch the complete documentation index at: https://docs.siro.ai/llms.txt
Use this file to discover all available pages before exploring further.
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 organization token
- Log into your Siro workspace as an admin
- Navigate to Person Icon → API Tokens
- Click Generate New API Token
- Store this securely — use it as the Bearer value below (this is your organization integration token, not a user OAuth access token)
API Base URL
Most API calls use:
https://functions.siro.ai/api-externalApi/v1
Authentication: Send the organization token as a Bearer token:
curl --request GET \
--url 'https://functions.siro.ai/api-externalApi/v1/core/mobile-events?pageSize=100' \
--header 'Authorization: Bearer <organization-api-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.
CRM entity IDs
- Siro-internal id (
id): The UUID Siro stores for a synced CRM row (account, engagement, opportunity, external user, etc.). Use this when an API accepts our primary key—for example when linking a recording to CRM entities—or when reading ids from webhooks and detail payloads.
- CRM-native id (
externalId): The identifier in your CRM (for example a Salesforce Id). When you target entities by externalId, also send integrationConnectionId so Siro knows which CRM connection that id belongs to.
People: Siro Users vs External Users
- Siro User: Someone who can sign into your Siro workspace (web or mobile). This maps to a
SiroUser in our database. Examples: OAuth app owner, recording userId on recording detail, webhook siroUserId.
- External User (same concept as CRM User): The synced representation of a rep or roster row from your CRM—the API resource named
User. Sync payloads include externalId, email, and name; Siro maps External Users to Siro Users for attribution (automatic match or Settings → Integrations → User Mapping).
| Your System | In Siro / API | Purpose |
|---|
| Sales rep / roster row in CRM | External User (User) | CRM-side identity; maps to a Siro User for workspace login and attribution |
| 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 External Users to Siro Users
User linking happens automatically. When you sync engagements or opportunities, include each rep’s CRM identifiers on User payloads (externalId, email, and name). Siro maps External Users to Siro Users by email or name match. Manual override is 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 <organization-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 <organization-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 integrations use your organization API token. To call Get Recording Details (section 4.3) or Get Entity Extractions (section 4.5), you also need OAuth setup below. If webhooks plus engagement polling are enough for your use case, you can skip OAuth.
1. Create an OAuth App
Endpoint: POST /v1/core/oauth/apps • Full docs
Provide appName, owner (Siro 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 (Siro User id), 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.
siroUserId — Siro User id for the rep associated with the recording.
crm.users[] — linked External Users; id is Siro-internal for that user row, externalId is the id from your CRM (when set).
crm.engagement / crm.opportunity / crm.account — each includes Siro-internal id plus CRM-native externalId where applicable.
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): (userId is the Siro User id; see People: Siro Users vs External Users in Step 2.)
{
"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.