Calls API Guide

Calls API Guide

The Calls API allows you to access call records, download recordings, and retrieve transcripts and AI-generated insights from calls made through Sure Send CRM.

Overview

Call records contain:

  • Basic call metadata (phone number, duration, direction)
  • Recording file (downloadable via signed URL)
  • Full transcript with speaker labels
  • AI-generated intelligence (summary, sentiment, topics)

Retrieving Calls

List All Calls

Endpoint: GET /api/partner/calls

curl "https://api.suresend.ai/api/partner/calls?page=1&limit=25" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Query Parameters:

  • page - Page number (default: 1)
  • limit - Items per page (default: 25, max: 100)

Response:

{
  "calls": [
    {
      "id": "call-uuid",
      "personId": "person-uuid",
      "userId": "user-uuid",
      "phone": "+1-555-1234",
      "duration": 180,
      "isIncoming": false,
      "outcome": "answered",
      "hasRecording": true,
      "recordingUrl": "https://storage.example.com/signed-url...",
      "recordingUrlExpiresIn": 3600,
      "hasTranscript": true,
      "conversationSummary": "Customer called to inquire about pricing options...",
      "conversationTopics": ["pricing", "features", "timeline"],
      "sentimentLabel": "positive",
      "sentimentScore": 0.75,
      "intelligenceProcessed": true,
      "intelligenceProcessedAt": "2025-12-01T10:00:00Z",
      "createdAt": "2025-12-01T09:30:00Z",
      "updatedAt": "2025-12-01T10:00:00Z"
    }
  ],
  "meta": {
    "total_count": 150,
    "current_page": 1,
    "total_pages": 6,
    "per_page": 25
  }
}

Get a Specific Call

Endpoint: GET /api/partner/calls/{id}

curl https://api.suresend.ai/api/partner/calls/call-uuid \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Downloading Call Recordings

When a call has a recording available, the call response includes a signed URL that you can use to download the audio file.

Checking for Recordings

Look for these fields in the call response:

{
  "hasRecording": true,
  "recordingUrl": "https://storage.example.com/signed-url...",
  "recordingUrlExpiresIn": 3600
}
  • hasRecording - Boolean indicating if a recording exists
  • recordingUrl - Signed URL to download the recording (only present if hasRecording is true)
  • recordingUrlExpiresIn - Seconds until the URL expires (always 3600 = 1 hour)

Downloading the Recording

# Get the call to retrieve the recording URL
curl https://api.suresend.ai/api/partner/calls/call-uuid \
  -H "Authorization: Bearer YOUR_API_TOKEN"

# Download the recording using the recordingUrl from the response
curl -o recording.mp3 "https://storage.example.com/signed-url..."

Important Notes on Recording URLs

  1. URLs expire after 1 hour - If you need to access the recording later, download and store it
  2. Get a fresh URL - Simply fetch the call again to get a new signed URL
  3. Format - Recordings are MP3 audio files
  4. No authentication needed - The signed URL includes temporary credentials

Example: Download and Store Recording

const axios = require('axios');
const fs = require('fs');

const API_TOKEN = process.env.API_TOKEN;
const API_URL = 'https://api.suresend.ai/api/partner';

async function downloadRecording(callId, outputPath) {
  // Get the call to retrieve the recording URL
  const callResponse = await axios.get(`${API_URL}/calls/${callId}`, {
    headers: { Authorization: `Bearer ${API_TOKEN}` }
  });

  const call = callResponse.data;

  if (!call.hasRecording) {
    console.log('No recording available for this call');
    return null;
  }

  console.log(`Recording URL expires in ${call.recordingUrlExpiresIn} seconds`);

  // Download the recording
  const recordingResponse = await axios.get(call.recordingUrl, {
    responseType: 'stream'
  });

  // Save to file
  const writer = fs.createWriteStream(outputPath);
  recordingResponse.data.pipe(writer);

  return new Promise((resolve, reject) => {
    writer.on('finish', () => {
      console.log(`Recording saved to ${outputPath}`);
      resolve(outputPath);
    });
    writer.on('error', reject);
  });
}

// Usage
downloadRecording('call-uuid', './recordings/call-123.mp3');

Accessing Call Transcripts

For calls with transcription enabled, you can retrieve the full transcript with speaker labels.

Checking for Transcripts

Look for the hasTranscript field in the call response:

{
  "hasTranscript": true
}

Get Full Transcript

Endpoint: GET /api/partner/calls/{id}/transcript

curl https://api.suresend.ai/api/partner/calls/call-uuid/transcript \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Response (200 OK):

{
  "transcript": "[Agent]: Hello, thank you for calling Sure Send. How can I help you today?\n[Customer]: Hi, I'm interested in learning more about your pricing plans.\n[Agent]: Of course! Let me walk you through our options...",
  "hasTranscript": true
}

Response (404 Not Found):

{
  "errorMessage": "No transcript available"
}

Example: Get Call with Transcript

async function getCallWithTranscript(callId) {
  // Get basic call info
  const callResponse = await axios.get(`${API_URL}/calls/${callId}`, {
    headers: { Authorization: `Bearer ${API_TOKEN}` }
  });

  const call = callResponse.data;

  // Get transcript if available
  if (call.hasTranscript) {
    const transcriptResponse = await axios.get(
      `${API_URL}/calls/${callId}/transcript`,
      { headers: { Authorization: `Bearer ${API_TOKEN}` } }
    );
    call.fullTranscript = transcriptResponse.data.transcript;
  }

  return call;
}

AI-Generated Intelligence

Sure Send CRM automatically analyzes calls to extract insights. These are included directly in the call response.

Intelligence Fields

FieldTypeDescription
conversationSummarystringAI-generated 2-3 sentence summary of the call
conversationTopicsarrayKey topics discussed (e.g., ["pricing", "features"])
sentimentLabelstringOverall sentiment: "positive", "negative", or "neutral"
sentimentScorenumberSentiment score from -1.0 (negative) to 1.0 (positive)
intelligenceProcessedbooleanWhether AI analysis has completed
intelligenceProcessedAtstringISO timestamp when analysis completed

Example Response with Intelligence

{
  "id": "call-uuid",
  "phone": "+1-555-1234",
  "duration": 300,
  "hasRecording": true,
  "hasTranscript": true,
  "conversationSummary": "Customer called to inquire about enterprise pricing. Agent explained the three tiers and customer expressed interest in the professional plan. Follow-up meeting scheduled for next week.",
  "conversationTopics": ["pricing", "enterprise features", "demo request"],
  "sentimentLabel": "positive",
  "sentimentScore": 0.82,
  "intelligenceProcessed": true,
  "intelligenceProcessedAt": "2025-12-01T10:05:00Z"
}

Checking Intelligence Status

async function waitForIntelligence(callId, maxAttempts = 10) {
  for (let i = 0; i < maxAttempts; i++) {
    const response = await axios.get(`${API_URL}/calls/${callId}`, {
      headers: { Authorization: `Bearer ${API_TOKEN}` }
    });

    const call = response.data;

    if (call.intelligenceProcessed) {
      console.log('Intelligence ready:', call.conversationSummary);
      return call;
    }

    console.log(`Waiting for intelligence processing... (attempt ${i + 1})`);
    await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5 seconds
  }

  console.log('Intelligence processing timed out');
  return null;
}

Creating Call Records

Endpoint: POST /api/partner/calls

Create a call record for external calls (e.g., from your own phone system):

curl -X POST https://api.suresend.ai/api/partner/calls \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "personId": "person-uuid",
    "phone": "+1-555-1234",
    "isIncoming": false,
    "outcome": "answered",
    "duration": 180,
    "note": "Discussed pricing options"
  }'

Request Body:

FieldTypeRequiredDescription
personIdstringYesUUID of the person
phonestringYesPhone number
userIdstringNoUser who made/received the call
isIncomingbooleanNoTrue if incoming call
outcomestringNoCall outcome (answered, voicemail, no-answer, etc.)
durationintegerNoCall duration in seconds
notestringNoNotes about the call
toNumberstringNoDestination number
fromNumberstringNoOrigin number

Updating Call Records

Endpoint: PUT /api/partner/calls/{id}

curl -X PUT https://api.suresend.ai/api/partner/calls/call-uuid \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "note": "Updated notes: Customer requested callback next week",
    "outcome": "callback-scheduled"
  }'

Common Use Cases

1. Export Calls with Recordings

async function exportCallsWithRecordings(outputDir) {
  let page = 1;
  let hasMore = true;

  while (hasMore) {
    const response = await axios.get(`${API_URL}/calls`, {
      params: { page, limit: 100 },
      headers: { Authorization: `Bearer ${API_TOKEN}` }
    });

    const { calls, meta } = response.data;

    for (const call of calls) {
      if (call.hasRecording) {
        const filename = `${outputDir}/call-${call.id}.mp3`;
        await downloadRecording(call.recordingUrl, filename);
      }
    }

    hasMore = page < meta.total_pages;
    page++;
  }
}

2. Analyze Call Sentiment Trends

async function analyzeSentimentTrends() {
  const response = await axios.get(`${API_URL}/calls`, {
    params: { limit: 100 },
    headers: { Authorization: `Bearer ${API_TOKEN}` }
  });

  const calls = response.data.calls.filter(c => c.intelligenceProcessed);

  const stats = {
    positive: calls.filter(c => c.sentimentLabel === 'positive').length,
    neutral: calls.filter(c => c.sentimentLabel === 'neutral').length,
    negative: calls.filter(c => c.sentimentLabel === 'negative').length,
    averageScore: calls.reduce((sum, c) => sum + (c.sentimentScore || 0), 0) / calls.length
  };

  console.log('Sentiment Analysis:', stats);
  return stats;
}

3. Search Transcripts for Keywords

async function searchTranscripts(keyword) {
  const results = [];
  let page = 1;
  let hasMore = true;

  while (hasMore) {
    const response = await axios.get(`${API_URL}/calls`, {
      params: { page, limit: 100 },
      headers: { Authorization: `Bearer ${API_TOKEN}` }
    });

    const { calls, meta } = response.data;

    for (const call of calls) {
      if (call.hasTranscript) {
        const transcriptResponse = await axios.get(
          `${API_URL}/calls/${call.id}/transcript`,
          { headers: { Authorization: `Bearer ${API_TOKEN}` } }
        );

        if (transcriptResponse.data.transcript.toLowerCase().includes(keyword.toLowerCase())) {
          results.push({
            callId: call.id,
            personId: call.personId,
            date: call.createdAt,
            summary: call.conversationSummary
          });
        }
      }
    }

    hasMore = page < meta.total_pages;
    page++;
  }

  return results;
}

// Usage
searchTranscripts('pricing').then(results => {
  console.log(`Found ${results.length} calls mentioning pricing`);
});

Best Practices

Recording Downloads

  1. Cache recordings locally - URLs expire after 1 hour
  2. Check hasRecording first - Don't assume all calls have recordings
  3. Handle large files - Use streaming for downloads
  4. Respect storage limits - Implement retention policies

Transcripts

  1. Check hasTranscript first - Not all calls have transcripts
  2. Use separate endpoint - Full transcripts are retrieved via /transcript
  3. Parse speaker labels - Transcripts use [Agent]: and [Customer]: format

Intelligence Data

  1. Check intelligenceProcessed - AI analysis may not be immediate
  2. Handle null values - Fields may be null if processing failed
  3. Use for insights - Leverage sentiment and topics for analytics

Error Handling

404 Not Found (Call):

{
  "errorMessage": "Call not found"
}

404 Not Found (Transcript):

{
  "errorMessage": "No transcript available"
}

401 Unauthorized:

{
  "errorMessage": "Invalid or expired token"
}

Next Steps

Need Help?