partners@snakk.ai)1. DEFINE → Write the JSON specification for your integration
2. SUBMIT → POST to /api/partner/integrations
3. REVIEW → Snakk team tests it (1-3 days)
4. LIVE → Available to all customers ✓https://api.snakk.ai| Context | When | Example |
|---|---|---|
during_call | AI uses it as a tool during conversation | "Look up customer in CRM" |
end_of_call | Runs automatically after the call | "Save call summary" |
both | Either | "Send SMS" (during or after) |
{
"slug": "acme-crm",
"name": "Acme CRM",
"description": "Our popular CRM system for SMBs",
"category": "crm",
"auth_type": "api_key",
"api_key_config": {
"fields": [
{
"key": "api_key",
"label": "API Key",
"required": true,
"secret": true
},
{
"key": "subdomain",
"label": "Subdomain (e.g. yourcompany)",
"required": true,
"secret": false
}
]
},
"actions": [
{
"slug": "lookup-contact",
"name": "Lookup Contact",
"description": "Find a contact by phone, email, or name",
"usage_context": "during_call",
"execution_type": "http",
"http_config": {
"url": "https://{{subdomain}}.acme.com/api/v1/contacts/search?q={{query}}",
"method": "GET",
"headers": {
"Authorization": "Bearer {{api_key}}",
"Content-Type": "application/json"
},
"response_mapping": {
"found": "$.results.length > 0",
"contact_id": "$.results[0].id",
"name": "$.results[0].full_name",
"email": "$.results[0].email",
"phone": "$.results[0].phone"
}
},
"parameters_schema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Phone number, email, or name to search"
}
},
"required": ["query"]
},
"agent_instructions": "MANDATORY: Look up the caller at the start of every conversation using the customer's phone number to identify them.",
"mock_response": {
"found": true,
"contact_id": "abc123",
"name": "Ola Nordmann",
"email": "ola@firma.no",
"phone": "+4712345678"
}
}
]
}| Field | Type | Required | Description |
|---|---|---|---|
slug | string | ✅ | Unique identifier (kebab-case). Auto-prefixed with partner- |
name | string | ✅ | Display name (shown to customers) |
description | string | ✅ | Short description of the service |
category | string | ✅ | See category list |
auth_type | string | ✅ | oauth2, api_key, or none |
oauth_config | object | ⚠️ | Required if oauth2 |
api_key_config | object | ⚠️ | Required if api_key |
| Field | Type | Required | Description |
|---|---|---|---|
slug | string | ✅ | Unique per provider (kebab-case) |
name | string | ✅ | Display name |
description | string | ✅ | Used as the description for the AI |
usage_context | string | ✅ | during_call, end_of_call, or both |
execution_type | string | ✅ | http or flow (built_in reserved for first-party) |
http_config | object | ⚠️ | Required if http |
flow_definition | object | ⚠️ | Required if flow |
parameters_schema | object | ✅ | JSON Schema for input parameters |
agent_instructions | string | ⚠️ | Recommended for during_call actions |
mock_response | object | ✅ | Required — returned in test mode |
crm, accounting, calendar, booking, email, sms, communication,
helpdesk, ecommerce, healthcare, productivity, marketing, hr, other{
"auth_type": "oauth2",
"oauth_config": {
"authorization_url": "https://acme.com/oauth/authorize",
"token_url": "https://acme.com/oauth/token",
"scopes": ["read", "write"],
"userinfo_url": "https://acme.com/api/me",
"extra_params": {
"access_type": "offline",
"prompt": "consent"
}
}
}{SLUG_UPPER}_CLIENT_ID and {SLUG_UPPER}_CLIENT_SECRET. Send them via encrypted email to partners@snakk.ai after approval.https://api.snakk.ai/api/integrations/oauth/partner-{slug}/callback{
"auth_type": "api_key",
"api_key_config": {
"fields": [
{ "key": "api_key", "label": "API Key", "required": true, "secret": true },
{ "key": "subdomain", "label": "Subdomain", "required": true, "secret": false }
]
}
}secret: true hides the field as a password. Values are stored encrypted and available as template variables in http_config.{
"execution_type": "http",
"http_config": {
"url": "https://api.example.com/v1/resource/{{id}}",
"method": "POST",
"headers": {
"Authorization": "Bearer {{api_key}}",
"Content-Type": "application/json"
},
"body_template": {
"name": "{{customer_name}}",
"email": "{{customer_email}}",
"metadata": {
"source": "snakk-ai",
"phone": "{{caller_phone}}"
}
},
"response_mapping": {
"success": "$.status == 'created'",
"id": "$.data.id",
"message": "$.message"
},
"timeout_ms": 5000
}
}{{param_name}} — from agent input{{api_key}}, {{subdomain}} — from credentials{{caller_phone}} — from call context{
"execution_type": "flow",
"flow_definition": {
"nodes": [
{ "id": "trigger", "type": "trigger", "data": {} },
{
"id": "step1",
"type": "http_request",
"data": {
"method": "GET",
"url": "https://api.example.com/check/{{trigger.id}}"
}
},
{
"id": "condition1",
"type": "condition",
"data": { "expression": "{{step1.found}} == true" }
},
{
"id": "return_success",
"type": "return",
"data": { "output_mapping": { "result": "{{step1.data}}" } }
}
],
"edges": [
{ "source": "trigger", "target": "step1" },
{ "source": "step1", "target": "condition1" },
{ "source": "condition1", "target": "return_success", "sourceHandle": "true" }
]
}
}mock_response. This is returned when the customer tests the agent in the platform UI (instead of calling your real API).{
"slug": "create-contact",
"mock_response": {
"success": true,
"contact_id": "mock-12345",
"name": "Test Customer",
"message": "Contact created (TEST MODE)"
}
}{
"success": true,
"provider_id": "uuid",
"slug": "partner-acme-crm",
"status": "pending_review",
"message": "Integration submitted for review."
}agent_instructions are clear and helpful for the AIX-API-Key: YOUR_PARTNER_KEY.POST /api/partner/integrations201 Created with provider_id and status: "pending_review"GET /api/partner/integrations{
"integrations": [
{
"id": "uuid",
"slug": "partner-acme-crm",
"name": "Acme CRM",
"is_active": true,
"actions": [...]
}
]
}PATCH /api/partner/integrations/:providerId{
"name": "Updated Name",
"description": "New description",
"actions": [
{
"id": "action-uuid",
"name": "Updated Action",
"description": "...",
"parameters_schema": {...},
"http_config": {...},
"mock_response": {...}
}
]
}GET /api/partner/integrations/:providerId/stats{
"provider": "Acme CRM",
"slug": "partner-acme-crm",
"installations": 34,
"stats": {
"total_calls": 1247,
"successful_calls": 1225,
"success_rate": 98.2,
"avg_latency_ms": 380,
"period": "last_30_days"
}
}description and agent_instructions are used by OpenAI to determine when and how the action should be called.{
"description": "Function for getting user data",
"agent_instructions": "Use this function"
}{
"description": "Look up a customer in the CRM by phone, email, or name. Returns contact details if found.",
"agent_instructions": "MANDATORY: Call this at the START of every conversation using the caller's phone number {{customer.number}}. Do not greet the customer until you have their information. If found, use their name in the greeting."
}{
"type": "object",
"properties": {
"phone": {
"type": "string",
"description": "Customer phone number in E.164 format (e.g. +4712345678)"
},
"service_type": {
"type": "string",
"enum": ["consultation", "support", "sales"],
"description": "Type of meeting requested"
},
"duration_minutes": {
"type": "integer",
"default": 30,
"minimum": 15,
"maximum": 120,
"description": "Meeting duration in minutes"
}
},
"required": ["phone", "service_type"]
}{
"found": true,
"<entity_id>": "...",
"...other fields"
}{
"found": false,
"message": "No customer found"
}{
"success": true,
"<entity_id>": "...",
"message": "Human-readable confirmation"
}{
"success": false,
"error": "Specific error message"
}name and description can be in any language (these are shown to customers)name should generally stay in English (used by AI internally)mock_response can include localized text where appropriatehttp://)10.x, 172.16-31.x, 192.168.x, 127.x, 169.254.x)localhost, 0.0.0.0, or cloud metadata IPshttp_config.timeout_ms)built_in execution type (reserved for first-party)/stats endpoint)partners@snakk.ai.{
"slug": "acme-crm",
"name": "Acme CRM",
"description": "Cloud-based CRM for sales and support teams",
"category": "crm",
"auth_type": "api_key",
"api_key_config": {
"fields": [
{ "key": "api_key", "label": "API Key", "required": true, "secret": true },
{ "key": "subdomain", "label": "Subdomain", "required": true, "secret": false }
]
},
"actions": [
{
"slug": "lookup-contact",
"name": "Lookup Contact",
"description": "Find a contact in Acme CRM by phone, email, or name",
"usage_context": "during_call",
"execution_type": "http",
"http_config": {
"url": "https://{{subdomain}}.acme.com/api/v1/contacts/search?q={{query}}",
"method": "GET",
"headers": {
"Authorization": "Bearer {{api_key}}"
},
"response_mapping": {
"found": "$.total > 0",
"contact_id": "$.contacts[0].id",
"name": "$.contacts[0].full_name",
"email": "$.contacts[0].email",
"phone": "$.contacts[0].phone"
}
},
"parameters_schema": {
"type": "object",
"properties": {
"query": { "type": "string", "description": "Phone, email, or name" }
},
"required": ["query"]
},
"agent_instructions": "MANDATORY: Look up the caller using their phone number at the START of every conversation. Use their name in the greeting if found.",
"mock_response": {
"found": true,
"contact_id": "abc123",
"name": "Ola Nordmann",
"email": "ola@firma.no",
"phone": "+4712345678"
}
},
{
"slug": "create-contact",
"name": "Create Contact",
"description": "Create a new contact in Acme CRM",
"usage_context": "both",
"execution_type": "http",
"http_config": {
"url": "https://{{subdomain}}.acme.com/api/v1/contacts",
"method": "POST",
"headers": {
"Authorization": "Bearer {{api_key}}",
"Content-Type": "application/json"
},
"body_template": {
"full_name": "{{name}}",
"email": "{{email}}",
"phone": "{{phone}}",
"source": "voice-agent"
},
"response_mapping": {
"success": "$.id != null",
"contact_id": "$.id",
"message": "Contact created"
}
},
"parameters_schema": {
"type": "object",
"properties": {
"name": { "type": "string", "description": "Full name of the contact" },
"email": { "type": "string", "description": "Email address" },
"phone": { "type": "string", "description": "Phone number" }
},
"required": ["name"]
},
"agent_instructions": "Use this to create a new contact when the caller is not found in the CRM. Always confirm name and contact info before creating.",
"mock_response": {
"success": true,
"contact_id": "mock-456",
"message": "Contact created (TEST MODE)"
}
},
{
"slug": "log-call-summary",
"name": "Log Call Summary",
"description": "Save the call transcript and summary as a note in Acme CRM",
"usage_context": "end_of_call",
"execution_type": "http",
"http_config": {
"url": "https://{{subdomain}}.acme.com/api/v1/notes",
"method": "POST",
"headers": {
"Authorization": "Bearer {{api_key}}",
"Content-Type": "application/json"
},
"body_template": {
"phone": "{{caller_phone}}",
"subject": "Call from voice agent",
"body": "{{summary}}\n\n---\nFull transcript:\n{{transcript}}"
}
},
"parameters_schema": {
"type": "object",
"properties": {}
},
"mock_response": {
"success": true,
"note_id": "mock-note-789",
"message": "Note added to contact"
}
}
]
}