Meeting and call summaries via API

Getting a transcript is the easy part. Here's how to turn it into a structured meeting summary via API without breaking the budget on long calls.

4 min · · Updated · автоматизация · встречи

Getting a call transcript today isn't the hard part — almost any video conferencing tool or a dedicated speech-to-text service handles that. The hard part starts at the next step: turning 40 minutes of raw text into a structured summary with decisions and action items, without the cost ballooning on longer meetings.

Which call and which model

Send the finished transcript as text to /v1/chat/completions (if your infrastructure is already built around the OpenAI format) or /v1/messages (if the Anthropic style is more convenient). A one-hour meeting transcript usually runs 8-15 thousand words, roughly 12-20 thousand tokens, which fits comfortably within any model's context — Claude and GPT carry a 1,000,000-token window, GLM 128K, so even a three-hour multi-speaker workshop goes through as a single request, no chunking needed.

bash
curl https://api.zukko.pro/v1/chat/completions \
  -H "Authorization: Bearer fetch_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.6-sol",
    "messages": [
      {"role": "system", "content": "Summarize the meeting: a Decisions section, a Tasks section with owners, an Open Questions section. Do not restate lines verbatim."},
      {"role": "user", "content": "'"$(cat transcript.txt | jq -Rs .)"'"}
    ]
  }'

gpt-5.6-sol here is just an example: on Zukko it costs the same as claude-opus-5-5 ($0.30/$0.30 per 1M input/output tokens). If per-volume price matters more for summaries, test gpt-5.6-luna or glm-5.3 (both $0.10/$0.10) on your own recordings.

Structured output instead of a wall of text

A summary with no section breakdown is useless — nobody reads it end to end. A good way to get a machine-readable result is to ask the model to return JSON and render that into a template afterward, say a Notion card or a Telegram message:

bash
import requests, json

resp = requests.post(
    "https://api.zukko.pro/v1/chat/completions",
    headers={"Authorization": "Bearer fetch_your_key"},
    json={
        "model": "gpt-5.6-sol",
        "messages": [
            {"role": "system", "content": (
                "Return strict JSON shaped like "
                '{"decisions": [...], "tasks": [{"who": "", "what": ""}], "open_questions": [...]}. '
                "No text around the JSON."
            )},
            {"role": "user", "content": open("transcript.txt").read()},
        ],
    },
)
summary = json.loads(resp.json()["choices"][0]["message"]["content"])

Idempotency where the transcript arrives via webhook

If the summary job fires from a video conferencing webhook — say, a "recording ready" event — webhooks are often redelivered when the receiver times out. Without protection, the same call gets summarized and billed twice. The fix is an Idempotency-Key keyed on the meeting ID:

bash
curl https://api.zukko.pro/v1/chat/completions \
  -H "Authorization: Bearer fetch_your_key" \
  -H "Idempotency-Key: meeting-$MEETING_ID" \
  -H "Content-Type: application/json" \
  -d @payload.json

A webhook redelivery with the same body within 24 hours returns the already-computed response without a new charge — exactly the scenario this header exists for.

Long multi-hour recordings and cost

For recurring multi-hour workshops, it's worth estimating cost up front with the free token count, if you're using the Anthropic-style mode:

bash
curl https://api.zukko.pro/v1/messages/count_tokens \
  -H "Authorization: Bearer fetch_your_key" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{"model": "claude-sonnet-5", "messages": [{"role": "user", "content": "..."}]}'

If you're running hundreds of meetings a month — a call center or a sales team, say — a real saving is enabling caching for repeated operations: if the same transcript gets summarized twice with a fully identical request, for instance a pipeline retry after a client-side timeout, a request with the X-Zukko-Cache: true header (temperature: 0 also enables the cache, but only on models that accept that parameter; Claude models — claude-sonnet-5, claude-opus-5-5 — may reject a temperature other than 1 with a 400, so don't pass it to them) returns the cached response instantly and for free, flagged with X-Zukko-Cache: hit in the response; the cache only works on a fully identical request body, and such hits aren't written to /v1/usage. For chat, cache entries live up to 7 days, enough to cover typical same-day pipeline reruns.

Budget control across teams

If meeting summaries are triggered by several teams — sales, support, engineering — it makes sense to issue each one its own key with its own monthly cap in the dashboard (https://zukko.pro/app/api-keys). That guards against overspend. What it won't do is split spend by team via GET /v1/usage: the history there covers the whole account (all keys together), there's no per-key filter, and the balance is one per account too:

bash
curl https://api.zukko.pro/v1/usage \
  -H "Authorization: Bearer fetch_sales_team_key"

The endpoint returns the account's cursor-paginated spend history (fields created_at, model, input_tokens, output_tokens, total_tokens, cost_cents, next_cursor). To split spend by team, log X-Zukko-Cost-Micros from every non-streaming response on your side along with the key name — or set up a separate account per team.

Errors specific to this scenario

429 key_daily_limit_reached most likely means someone wired up summarization not just for the final recording but for every intermediate stream chunk. A 402 with the insufficient-balance message means the request never reached a model at all — no summary gets produced, and the pipeline should surface that as an explicit notification to the owner rather than let the job fail silently. If a response cuts off mid-summary, it's almost always max_tokens, not an account-level token limit — for a long meeting with a detailed task list, set max_tokens with headroom, say 4000, rather than leaving the default.

Bottom line: one model picked on price and quality against your own recordings, JSON on output, idempotency keyed on the meeting ID, and separate capped keys per team (plus your own per-key spend log) — with that setup, meeting summaries run at scale without billing surprises or duplicate records.

zukko

Pay 25×
less

for Claude Code & ChatGPT

One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.

Get API keyDocumentation

api.zukko.pro · fetch_*

Automated meeting summaries with the Claude and GPT API · Zukko