Recipes

Meetings, transcripts & summaries

One recipe answers a whole family of questions - “what meetings has this contact had?”, “what was the sentiment?”, “where’s the summary?”, “give me the transcript.” They’re all reads: start from a contact, follow the association to the meeting, read the meeting’s AI summary, highlights and sentiment - then hop one more link to the recording for the transcript itself and the media. The same pattern works from a company or deal - pass ?associations=meeting on any of them.

Before you start

Two things carry through every step. These are all reads - meetings and recordings are ingested by the call integrations (Recall.ai, Fathom, Clari…), so there’s no create endpoint, and their AI fields fill in asynchronously (wait for the recording’s status_code: "TRANSCRIPT_DONE"). And like ai_about, the AI fields - and the raw transcript - come back as JSON-encoded strings to parse; ai_formatted_transcript is already an object.

Step 1 · List the meetings on a contact

Retrieve the contact and embed its meetings by passing ?associations=meeting. Embedded associations come back as {id, association_name} pairs - ids only.

Take a meeting id from associations.meeting.records into Step 2. Got several? Fetch them all in one call with Hydrate by IDs (object=meeting). More than 100 meetings on one record are paged with the dedicated associations endpoint.

GET /api/v1/objects/contact/records/{id}
curl 'https://api.dreamteamcrm.ai/api/v1/objects/contact/records/1015634?associations=meeting' \
  -H 'Authorization: Bearer <YOUR_TOKEN>'
{
  "id": 1015634,
  "type": "contact",
  "properties": {
    "first_name": "Ada",
    "last_name": "Chen",
    "email": "ada@example.com",
    "owner_id": 1000052
  },
  "associations": {
    "meeting": {
      "records": [
        { "id": 1090142, "association_name": "contact_meeting_assoc" },
        { "id": 1090143, "association_name": "contact_meeting_assoc" }
      ],
      "metadata": {
        "total": 2,
        "has_more": false
      }
    }
  },
  "created_at": "2026-08-10T09:57:24.713Z",
  "updated_at": "2026-08-28T22:21:16.889Z",
  "created_by": 1000052
}
The contact, with its meeting ids embedded

Step 2 · Read the meeting - summary, highlights, sentiment

Retrieve the meeting by an id from Step 1. It carries the meeting intelligence: ai_sentiment (Good / Neutral / Bad) as a plain value, and ai_meeting_summary, ai_meeting_highlights, ai_meeting_post_brief as JSON-encoded strings - parse each after reading. participants is a comma-separated list of attendee emails.

The meeting does not hold the transcript - that lives on the recording. Continue to Step 3 for the transcript and media.

GET /api/v1/objects/meeting/records/{id}
curl 'https://api.dreamteamcrm.ai/api/v1/objects/meeting/records/1090142' \
  -H 'Authorization: Bearer <YOUR_TOKEN>'
{
  "id": 1090142,
  "type": "meeting",
  "properties": {
    "title": "Analytical Engines - Q3 renewal call",
    "start_at": "2026-08-14T15:00:00Z",
    "end_at": "2026-08-14T15:30:00Z",
    "external": true,
    "user_id": 1000052,
    "participants": "sam@example.com, ada@example.com",
    "ai_sentiment": "Good",
    "ai_meeting_summary": "{\"meeting_type\":\"Check-in\",\"tags\":[{\"tag_type\":\"topic\",\"value\":\"Renewal\",\"render_type\":\"badge\"}],\"content\":[{\"title\":\"Summary\",\"icon_category\":\"lucide-file-text\",\"value\":\"Ada walked through the Q3 renewal timeline and two open blockers; agreed to follow up on pricing.\"}]}",
    "ai_meeting_highlights": "[{\"heading\":\"Renewal timeline\",\"highlight_callout\":\"Ada confirmed a Q3 renewal target.\",\"highlight_details\":\"...\",\"timestamp\":\"06:14\"}]",
    "ai_meeting_post_brief": "Sam walked Ada through the Q3 renewal plan and agreed to reconnect Monday after sharing pricing."
  },
  "created_at": "2026-08-14T15:31:02.221Z",
  "updated_at": "2026-08-14T15:48:10.984Z",
  "created_by": 1000052
}
The meeting, with AI summary, highlights, and sentiment (AI fields are JSON strings)

Step 3 · Follow the recording for the transcript

The transcript and media live on the recording, one link on from the meeting. It’s two calls - use the tabs to switch between them: first read the meeting’s recording association for the id, then retrieve the recording.

The recording gives you two transcript shapes: transcript (the raw provider transcript, a JSON-encoded string of segments) and ai_formatted_transcript (a cleaned object of speaker turns with timestamps). audio_url and video_url are time-limited signed URLs - fetch them promptly and don’t store the URL itself.

Wait for status_code: "TRANSCRIPT_DONE" before relying on the transcript fields.

2 calls
GET /api/v1/objects/meeting/records/{id}
# meeting → recording id
curl 'https://api.dreamteamcrm.ai/api/v1/objects/meeting/records/1090142?associations=recording' \
  -H 'Authorization: Bearer <YOUR_TOKEN>'
{
  "id": 1090142,
  "type": "meeting",
  "associations": {
    "recording": {
      "records": [
        {
          "id": 1090777,
          "association_name": "meeting_recording_assoc"
        }
      ],
      "metadata": {
        "total": 1,
        "has_more": false
      }
    }
  }
}
The meeting’s recording id (the meeting’s properties are also returned, omitted here)

See also

Retrieve a record and Hydrate by IDs are the endpoints this recipe composes - use them directly to test each call live. To discover every field on meeting or recording yourself, call Describe Object.