API · EN
API · EN

Start

IntroductionQuickstartAuthenticationCore concepts

Guides

Uploading callsGetting resultsWebhooksPagination and search

Details

ErrorsRate limits and billing
API reference
aftertalk.coPricingContactPolski

Quickstart

Upload your first call and read the transcript.

Upload a recording, wait for it to process, and read the result. You need an API key — create one in the app under Organization → Settings → API keys (see authentication) — and a recording; the examples use call.wav. The shell steps use curl 7.76 or newer and jq to pick ids out of the responses.

1. Set your key and pick a project

export AFTERTALK_KEY="at_live_..."
export BASE="https://app.aftertalk.co/api"

# The first project in your organization. GET /v1/projects lists them all.
export PROJECT_ID=$(curl -sS --fail-with-body "$BASE/v1/projects" \
  -H "X-API-Key: $AFTERTALK_KEY" | jq -r '.[0].id')
echo "$PROJECT_ID"

2. Upload the recording

UPLOAD=$(curl -sS -X POST "$BASE/v1/projects/$PROJECT_ID/calls/upload" \
  -H "X-API-Key: $AFTERTALK_KEY" \
  -F "file=@call.wav;type=audio/wav")
export JOB_ID=$(echo "$UPLOAD" | jq -r '.jobId // .existingJobId')

if [ "$JOB_ID" = null ]; then
  echo "Upload failed: $(echo "$UPLOAD" | jq -r '.message')"
else
  echo "$JOB_ID"
fi

The format check reads the part's Content-Type, so set it with ;type= — curl would otherwise send application/octet-stream, which is rejected with 400. If the same audio is already in the project, the upload returns 409 with the original job as existingJobId, which the jq filter falls back to. Any other error has neither, so the check prints the API's message instead of carrying on with null.

{ "jobId": "8f14e45f-ea0f-4e21-9c1a-2b3c4d5e6f70", "status": "PENDING", "submittedAt": "2026-07-25T10:00:00Z" }

3. Wait for processing

Poll the job every few seconds until it leaves PENDING and PROCESSING:

while :; do
  JOB=$(curl -sS "$BASE/v1/projects/$PROJECT_ID/calls/jobs/$JOB_ID" \
    -H "X-API-Key: $AFTERTALK_KEY")
  STATUS=$(echo "$JOB" | jq -r '.status')
  [ "$STATUS" = PENDING ] || [ "$STATUS" = PROCESSING ] || break
  sleep 5
done

case "$STATUS" in
  COMPLETED | BILLING_FAILED)
    export TRANSCRIPT_ID=$(echo "$JOB" | jq -r '.transcriptId')
    echo "$STATUS $TRANSCRIPT_ID" ;;
  FAILED) echo "Processing failed: $(echo "$JOB" | jq -r '.errorMessage')" ;;
  *) echo "Request failed: $(echo "$JOB" | jq -r '.message')" ;;
esac

COMPLETED and BILLING_FAILED both have results to read. FAILED has no transcript — errorMessage says why. A failed request (a wrong key, an unknown job) returns the API's error body, whose status is the HTTP code, so it ends the loop too. See getting results for the full status list, or webhooks to skip polling entirely.

4. Read the result

curl -sS --fail-with-body "$BASE/v1/projects/$PROJECT_ID/calls/$TRANSCRIPT_ID" \
  -H "X-API-Key: $AFTERTALK_KEY" \
  | jq '{title, durationS, summary: .summary.summary.executiveSummary}'

The full response has the transcript as speaker-attributed turns, plus whatever analysis your project has configured: summary, classification, and templateAnalysis. Each of those can be missing on a successful call, so read them defensively.

The whole flow as a script

The same four steps, ready to save and run. A failed request stops the script with curl's status line and the API's error body:

quickstart.sh
#!/usr/bin/env bash
set -euo pipefail

BASE="https://app.aftertalk.co/api"
AUTH="X-API-Key: $AFTERTALK_KEY"

# 1. The first project in your organization.
PROJECT_ID=$(curl -sS --fail-with-body "$BASE/v1/projects" -H "$AUTH" | jq -r '.[0].id')

# 2. Upload. A 409 means this audio is already in the project; carry on with that job.
UPLOAD=$(curl -sS -X POST "$BASE/v1/projects/$PROJECT_ID/calls/upload" -H "$AUTH" \
  -F "file=@call.wav;type=audio/wav")
JOB_ID=$(echo "$UPLOAD" | jq -r '.jobId // .existingJobId')
if [ "$JOB_ID" = null ]; then
  echo "Upload failed: $(echo "$UPLOAD" | jq -r '.message')" >&2
  exit 1
fi

# 3. Poll until the job leaves PENDING / PROCESSING.
while :; do
  JOB=$(curl -sS --fail-with-body "$BASE/v1/projects/$PROJECT_ID/calls/jobs/$JOB_ID" -H "$AUTH")
  STATUS=$(echo "$JOB" | jq -r '.status')
  [ "$STATUS" = PENDING ] || [ "$STATUS" = PROCESSING ] || break
  sleep 5
done

if [ "$STATUS" = FAILED ]; then
  echo "Processing failed: $(echo "$JOB" | jq -r '.errorMessage')" >&2
  exit 1
fi

# 4. COMPLETED and BILLING_FAILED both have results.
TRANSCRIPT_ID=$(echo "$JOB" | jq -r '.transcriptId')
curl -sS --fail-with-body "$BASE/v1/projects/$PROJECT_ID/calls/$TRANSCRIPT_ID" -H "$AUTH" \
  | jq -r '.summary.summary.executiveSummary // "(no summary for this call)"'

Next

  • Uploading calls — formats, speaker roles, duplicate handling
  • Getting results — job statuses and partial analysis
  • Webhooks — get told when a call is ready instead of polling
  • Errors — what the status codes mean

Introduction

Upload calls and get transcripts, analysis, and insights over HTTP.

Authentication

Organization API keys and the X-API-Key header.

On this page

1. Set your key and pick a project2. Upload the recording3. Wait for processing4. Read the resultThe whole flow as a scriptNext