Documentation/API Reference

    API Reference

    Build custom integrations and automate workflows with Meetric's REST API. Access conversations, insights and more programmatically.

    Getting Started#

    RESTful

    Standard HTTP methods and JSON responses

    Secure

    Token-based authentication with scoped access

    Fast

    Low latency with global CDN

    Base URL#

    text
    REST API: http://127.0.0.1:44449/api/v1/rest

    Authoritative API schema:

    text
    OpenAPI spec: http://127.0.0.1:44449/api/v1/rest/openapi.json

    Note

    The interactive API documentation page in Settings loads this OpenAPI spec.

    Authentication#

    Authenticate REST API requests with an API token:

    API Key Authentication
    curl -X GET "http://127.0.0.1:44449/api/v1/rest/conversations" \
      -H "Authorization: Bearer mt_your_api_token"

    Getting your API key:

    1. Navigate to Settings → API and open the API tokens section
    2. Click "Create API Token"
    3. Name your key (e.g., "Production Integration")
    4. Select token scopes (for example conversations, transcripts, insights)
    5. Copy the key (shown only once)
    6. Store securely - treat like a password

    Warning

    Never commit API keys to version control or expose them in client-side code. Rotate keys regularly and revoke compromised keys immediately.

    Rate Limits#

    API tokens enforce per-token rate limits and daily conversation quotas.

    Current Limits#

    API Token Defaults

    Sustained: 60 requests/minute
    Burst: Daily quota: 1000 unique conversations

    Limits are configured per token. The API returns HTTP 429 when the per-minute limit is hit:

    json
    {
      "statusCode": 429,
      "message": "Rate limit exceeded. Please try again later.",
      "retryAfter": 60
    }

    Tip

    Use exponential backoff and honor the `retryAfter` value when present.

    Endpoints Overview#

    Partner REST API endpoints organized by capability.

    Conversations

    Read conversation data with token scopes and filters

    GET/rest/conversationsList conversations (cursor pagination)
    GET/rest/conversations/:idGet conversation details
    GET/rest/conversations/:id/transcriptGet transcript (scope: transcripts)
    GET/rest/conversations/:id/insightsGet insights (scope: insights)
    GET/rest/conversations/:id/recording-urlGet recording URL (scope: recordings)

    Reference Data

    Fetch account-scoped directory entities

    GET/rest/accountGet account and branding context
    GET/rest/usersList users (scope: users)
    GET/rest/teamsList teams (scope: teams)
    GET/rest/departmentsList departments (scope: departments)

    Webhooks

    Inspect delivery status for token webhooks

    GET/rest/webhooks/deliveriesList recent webhook deliveries

    Note

    Endpoint availability is scope-based. If a token does not include a required scope, the API returns a forbidden response.

    Conversations API#

    Comprehensive examples for working with conversations.

    List Conversations#

    Request
    GET /api/v1/rest/conversations?limit=25&department_id=<department_uuid>
    
    curl -X GET "http://127.0.0.1:44449/api/v1/rest/conversations?limit=25" \
      -H "Authorization: Bearer mt_your_api_token"
    Response
    {
      "conversations": [
        {
          "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
          "title": "Discovery call - Acme",
          "company": "Acme",
          "date": "2024-01-15T10:30:00Z",
          "duration": 3600,
          "medium": "call",
          "sentiment": "positive",
          "conversation_type": "sales",
          "department": {
            "id": "11111111-0000-0000-0000-000000000001",
            "name": "B2B Sales"
          },
          "user": {
            "id": "67c869eb-30b1-4eb3-bd2c-be8c912a9827",
            "name": "Erik Lindstrom",
            "email": "[email protected]"
          }
        }
      ],
      "pagination": {
        "has_more": false,
        "next_cursor": null,
        "limit": 25
      },
      "_meta": {
        "token_prefix": "mt_ab12cd34",
        "timestamp": "2026-02-08T00:00:00.000Z"
      }
    }

    Query Parameters:

    limitinteger
    Number of results (max 25)(default: 25)
    cursorstring
    Pagination cursor from previous response
    department_iduuid
    Filter by department
    mediumstring
    Filter by medium (call, video, email, chat, live)
    date_fromdatetime
    Filter from ISO date-time
    date_todatetime
    Filter to ISO date-time
    user_iduuid
    Filter by conversation owner

    Insights API#

    Get Conversation Insights#

    Request
    GET /api/v1/rest/conversations/:id/insights
    
    curl -X GET "http://127.0.0.1:44449/api/v1/rest/conversations/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/insights" \
      -H "Authorization: Bearer mt_your_api_token"
    Response
    {
      "conversation_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
      "insights": [
        {
          "id": "99999999-aaaa-bbbb-cccc-dddddddddddd",
          "insight_type": "kpi",
          "insight_text": "Customer requested SSO.",
          "kpi_slug": "sso",
          "kpi_label": "SSO",
          "impact": "high",
          "start_time_seconds": 120,
          "end_time_seconds": 165,
          "message_index": 14
        }
      ],
      "_meta": {
        "token_prefix": "mt_ab12cd34",
        "timestamp": "2026-02-08T00:00:00.000Z"
      }
    }

    Note

    You can also request insights inline from conversation details usinginclude_insights=true onGET /rest/conversations/:id when the token includes the insights scope.

    Webhooks#

    Receive real-time notifications when events occur. Configure webhook URLs from the API settings tab in Settings when creating or managing API tokens.

    Webhook Payload Structure#

    Delivery Headers
    X-Webhook-Signature: sha256=<HMAC signature>
    X-Webhook-Event: conversation.completed
    X-Webhook-Delivery-Id: <delivery uuid>
    X-Webhook-Timestamp: <unix timestamp>
    Example Webhook
    {
      "event": "conversation.completed",
      "timestamp": "2024-01-15T11:00:00Z",
      "data": {
        "conversation": {
          "id": "conv_xyz789",
          "title": "Client Discovery Call",
          "date": "2024-01-15T10:30:00Z",
          "duration": 1800,
          "medium": "call",
          "conversation_type": "sales",
          "summary": "Summary text...",
          "participants": [
            {
              "name": "Jane Client",
              "email": "[email protected]",
              "role": "customer"
            }
          ]
        }
      },
      "_meta": {
        "token_prefix": "mt_ab12cd34",
        "delivery_id": "del_456"
      }
    }

    Error Handling#

    The API uses standard HTTP status codes and returns error details in JSON format.

    HTTP Status Codes#

    200

    OK

    Request succeeded

    201

    Created

    Resource created successfully

    400

    Bad Request

    Invalid request parameters

    401

    Unauthorized

    Invalid, missing, inactive or expired API token

    403

    Forbidden

    Insufficient permissions

    404

    Not Found

    Resource not found

    429

    Too Many Requests

    Rate limit exceeded

    500

    Internal Server Error

    Server error

    Error Response Format#

    Error Response
    {
      "statusCode": 400,
      "message": "Account ID is required",
      "error": "Bad Request"
    }

    Common error messages:

    Invalid API tokenBearer token is unknown
    API token has been revokedToken was revoked and can no longer be used
    Token does not have the required scopeToken scope is missing for the endpoint
    Daily quota exceededToken reached the daily unique conversation quota
    Conversation not foundResource is missing or outside token/account scope

    Retry Logic#

    Implement exponential backoff for failed requests:

    Retry Example (Node.js)
    async function fetchWithRetry(url, options, maxRetries = 3) {
      for (let attempt = 0; attempt < maxRetries; attempt++) {
        try {
          const response = await fetch(url, options);
          
          if (response.status === 429) {
            const retryAfter = response.headers.get('Retry-After') || Math.pow(2, attempt);
            await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
            continue;
          }
          
          if (!response.ok) {
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
          }
          
          return await response.json();
        } catch (error) {
          if (attempt === maxRetries - 1) throw error;
          
          const delay = Math.pow(2, attempt) * 1000;
          await new Promise(resolve => setTimeout(resolve, delay));
        }
      }
    }

    Code Examples#

    Node.js Example#

    Complete Example
    const axios = require('axios');
    
    const API_TOKEN = process.env.MEETRIC_API_TOKEN;
    const BASE_URL = 'http://127.0.0.1:44449/api/v1/rest';
    
    const Meetric = axios.create({
      baseURL: BASE_URL,
      headers: {
        'Authorization': `Bearer ${API_TOKEN}`,
        'Content-Type': 'application/json'
      }
    });
    
    // List conversations with cursor pagination
    async function getConversations() {
      try {
        const response = await Meetric.get('/conversations', {
          params: {
            limit: 25,
            date_from: '2026-01-01T00:00:00.000Z'
          }
        });
        return response.data;
      } catch (error) {
        console.error('Error:', error.response?.data || error.message);
        throw error;
      }
    }
    
    (async () => {
      const conversations = await getConversations();
      const first = conversations.conversations?.[0];
      if (first) {
        const insights = await Meetric.get(`/conversations/${first.id}/insights`);
        console.log('Insights count:', insights.data.insights?.length || 0);
      }
    })();

    Python Example#

    Complete Example
    import requests
    import os
    
    API_TOKEN = os.environ['MEETRIC_API_TOKEN']
    BASE_URL = 'http://127.0.0.1:44449/api/v1/rest'
    
    class MeetricClient:
        def __init__(self, api_token):
            self.session = requests.Session()
            self.session.headers.update({
                'Authorization': f'Bearer {api_token}',
                'Content-Type': 'application/json'
            })
            self.base_url = BASE_URL
        
        def get_conversations(self, params=None):
            response = self.session.get(
                f'{self.base_url}/conversations',
                params=params
            )
            response.raise_for_status()
            return response.json()
    
        def get_insights(self, conversation_id):
            response = self.session.get(
                f'{self.base_url}/conversations/{conversation_id}/insights'
            )
            response.raise_for_status()
            return response.json()
    
    client = MeetricClient(API_TOKEN)
    
    # List conversations
    conversations = client.get_conversations({
        'limit': 25,
        'medium': 'call'
    })
    first = conversations.get('conversations', [None])[0]
    if first:
        insights = client.get_insights(first['id'])
        print(f"Found {len(insights.get('insights', []))} insights")

    Best Practices#

    Use Pagination

    Always paginate large result sets to avoid timeouts and reduce memory usage

    Cache Responses

    Cache API responses when data doesn't change frequently to reduce API calls

    Handle Errors Gracefully

    Implement proper error handling and retry logic with exponential backoff

    Secure API Keys

    Never expose API keys in client-side code or commit them to version control

    Use Webhooks

    For real-time updates, use webhooks instead of polling the API repeatedly

    Version Your API Calls

    Specify API version in requests to ensure compatibility with future changes

    Note

    Questions about the API? Email [email protected].