Overview
Speed.ai monitors your firm's own phone lines (RingCentral, Zoom and other phone systems). It records, transcribes and scores intake calls: whether each call was answered, whether the caller was a lead, whether a lost lead needs rescuing, and how the agent handled it. LawLink reads those calls so your intake reports and your AI assistant can use them.
Read-only. LawLink reads calls and never connects or changes your phone system. The only things it changes at Speed.ai are which lines it reads and how deeply Speed.ai processes them (see Phone Lines), plus history refreshes (lookbacks) you ask for.
Integration Steps
Get your firm's SpeedAPI credentials
Ask your Speed.ai contact for SpeedAPI credentials for your firm: a
client ID (it starts speed_api_) and a client secret.
They belong to the firm, not to one person.
Connect Speed.ai in LawLink
Go to Integrations → Speed.ai → Connect and enter the client ID and secret. LawLink checks them with Speed.ai before saving.
Colleagues: once one person at the firm has connected, everyone else can connect with both fields left blank. LawLink reuses the firm's saved credentials. Admins can also send a platform invite from Users → Invite to platforms.
Phone Lines and Processing Depth
Speed.ai only shares calls from lines LawLink is set to read, at a chosen depth. People with Can Connect set this on the Speed.ai page, next to Re-Connect:
- Recording: calls with their recordings
- Recording + transcript: adds the transcript
- Full analysis: adds agent scoring, lead and lead-rescue flags
- Not read by LawLink: stops LawLink reading the line. This does not affect other products using the same line.
⚠️ Cost: deeper processing may change what your firm pays Speed.ai. Check with Speed.ai before choosing full analysis on a busy line.
What You Can Do
Dates are read as UTC. A list without a start date covers the last 7 days. The in-app API explorer lists every endpoint.
Calls
List calls, filtered by answered, lead, lead rescue, transcribed or direction. Open one call with its transcript and analysis, or get a recording link.
GET /api/v1/speed-ai/calls?date_from=2026-10-14&answered=false
GET /api/v1/speed-ai/calls/{call_id}
GET /api/v1/speed-ai/calls/{call_id}/recording
Recording links last one hour. Download promptly, and do not store or forward the link.
Summaries and missed callers
Totals for a period: calls, answered, missed, leads, rescue calls and
average agent score, broken down by day, line and agent. Missed callers lists each person
who rang and was missed, with how many callback attempts were made and whether, and how
fast, anyone reached them afterwards. Pass your firm's time_zone so a day is
your day. Calls can also be searched by phone number or by words in the transcript.
GET /api/v1/speed-ai/calls/summary?date_from=2026-10-13&time_zone=America/New_York
GET /api/v1/speed-ai/calls/missed?date_from=2026-10-19
GET /api/v1/speed-ai/calls?query=4045551234
AI assistant and universal API
Your assistant reads these calls with the call_intake tool,
and through communications with platform=speed_ai. The
universal API serves them at /api/v1/universal/communications?platform_id=speed_ai.
API Usage
Call the APIs with your LawLink token
Every request carries your LawLink API token (from API Tokens) or your signed-in session. LawLink holds the firm's Speed.ai credentials, exchanges them for Speed's hourly token, retries rate-limited reads and never logs call content. Dates are ISO-8601; they are read as UTC unless you pass time_zone.
Request structure
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json # for PUT and POST
# Base URL
https://app.lawlink.ai/api/v1/speed-ai
🔑 Key points:
- An unknown query parameter is refused with
422 Unknown parameter(s): …rather than ignored, so a typo never returns an unfiltered list. - If Speed.ai stops accepting the firm's credentials, LawLink answers
403with"reason": "platform_authentication_failed"— reconnect Speed.ai. - Speed.ai's own call records are returned as Speed.ai sends them, minus the raw phone-provider payload and the recording URL (fetched separately).
Connect
The first person at the firm sends the client ID and secret Speed.ai issued. Colleagues send an empty body to reuse the firm's saved pair.
Example: connect with the firm's credentials
curl -X POST \
"https://app.lawlink.ai/api/v1/speed-ai/connect" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "client_id": "speed_api_42_ab12cd", "client_secret": "…" }'
Example: a colleague connects
curl -X POST \
"https://app.lawlink.ai/api/v1/speed-ai/connect" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
Response
{
"status": "success",
"message": "Speed.ai connected to Acme Injury Law.",
"firm": { "id": 42, "name": "Acme Injury Law" },
"reused_firm_credentials": true
}
Choose the lines LawLink reads
List the firm's phone lines, then set LawLink's depth on each: fetch_recording, transcribe, analyze, or filter to stop. Changing a line needs Can Connect and is refused over MCP. The firm's time zone comes back with an IANA name to use as time_zone below.
Example: the firm and its time zone
curl -X GET \
"https://app.lawlink.ai/api/v1/speed-ai/firm" \
-H "Authorization: Bearer ACCESS_TOKEN"
Response (excerpt)
{ "law_firm": { "id": 42, "name": "Acme Injury Law",
"time_zone": "Eastern Time (US & Canada)", "iana_time_zone": "America/New_York", … } }
Example: list lines
curl -X GET \
"https://app.lawlink.ai/api/v1/speed-ai/lines" \
-H "Authorization: Bearer ACCESS_TOKEN"
Example: read a line with full analysis
curl -X PUT \
"https://app.lawlink.ai/api/v1/speed-ai/view" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "line_id": "12", "pipeline_action": "analyze" }'
List and filter calls
Filters: answered, is_lead, rescue_call, transcribed (true/false), agent_score, direction, sort. Page with limit (≤100) and offset (a multiple of limit). Without date_from you get the last 7 days.
Example: yesterday's missed lead calls, firm time
curl -X GET \
"https://app.lawlink.ai/api/v1/speed-ai/calls?date_from=2026-10-19&date_to=2026-10-19T23:59:59&time_zone=America/New_York&answered=false&is_lead=true&limit=50" \
-H "Authorization: Bearer ACCESS_TOKEN"
Response shape
{
"phone_calls": [ { "id": 9811, … Speed.ai's call fields …, "recording_available": true,
"voip_metadata": { "law_firm_integration_id": 12, "integration_type": "Zoom", … } } ],
"pagination": { "current_page": 1, "next_page": 2, "total_pages": 3, "total_count": 214, "per_page": 50 }
}
Example: one call, with transcript and analysis
curl -X GET \
"https://app.lawlink.ai/api/v1/speed-ai/calls/9811" \
-H "Authorization: Bearer ACCESS_TOKEN"
Example: its recording (link valid one hour)
curl -X GET \
"https://app.lawlink.ai/api/v1/speed-ai/calls/9811/recording" \
-H "Authorization: Bearer ACCESS_TOKEN"
Find a caller's calls
query takes a phone number in any format (matched on its digits) or words to find in the caller's name, transcript or summary. Speed.ai has no search of its own, so LawLink reads the window page by page — up to max_pages pages of 100 — and says how many calls it searched.
Example: every call from one number this week
curl -X GET \
"https://app.lawlink.ai/api/v1/speed-ai/calls?query=%2B1%20(404)%20555-1234&date_from=2026-10-14" \
-H "Authorization: Bearer ACCESS_TOKEN"
Example: calls where a caller mentioned a refund
curl -X GET \
"https://app.lawlink.ai/api/v1/speed-ai/calls?query=refund&transcribed=true" \
-H "Authorization: Bearer ACCESS_TOKEN"
Response (excerpt)
{ "query": "+1 (404) 555-1234", "calls_searched": 312, "complete": true,
"phone_calls": [ … ] }
Summaries
Totals over a window — overall, by day (in time_zone), by line and by agent. Every call filter above works here too. If the window holds more than max_pages×100 calls, complete is false and note says so.
Example: this week, firm days
curl -X GET \
"https://app.lawlink.ai/api/v1/speed-ai/calls/summary?date_from=2026-10-13&time_zone=America/New_York" \
-H "Authorization: Bearer ACCESS_TOKEN"
Response (excerpt)
{
"window": { "start_time": "2026-10-13T04:00:00Z", "end_time": null, "time_zone": "America/New_York" },
"totals": { "calls": 214, "answered": 171, "missed": 43, "leads": 38, "rescue_calls": 6, "transcribed": 190, "with_recording": 205 },
"average_agent_score": 78.4, "scored_calls": 168,
"by_day": { "2026-10-13": { "calls": 41, "answered": 33, "missed": 8, "leads": 7, "rescue_calls": 1 }, … },
"by_line": { "12": { … } }, "by_agent": { "Ann Lee": { … } },
"complete": true
}
Missed callers and callbacks
One row per caller who was missed: how many times, lead and rescue flags, how many callback attempts the firm made, and whether a later answered call with the same number reached them — the firm calling back, or the caller getting through on another try. Callers nobody reached come first. A callback made from a mobile phone or another system is not visible here.
Example: since yesterday morning
curl -X GET \
"https://app.lawlink.ai/api/v1/speed-ai/calls/missed?date_from=2026-10-19&time_zone=America/New_York" \
-H "Authorization: Bearer ACCESS_TOKEN"
Response (excerpt)
{
"missed_calls": 9, "callers_not_reached": 2, "missed_without_a_number": 0,
"callers": [
{ "number": "+14045551234", "caller_name": "Jane Roe", "missed": 2,
"last_missed_at": "2026-10-19 09:30", "is_lead": true, "rescue_call": true,
"callback_attempts": 1, "reached_at": null, "reached_by": "not reached in this window" },
{ "number": "+17705550000", "missed": 1, "last_missed_at": "2026-10-19 11:00",
"callback_attempts": 1, "reached_at": "2026-10-19 11:25", "reached_by": "firm called back", "minutes_to_reach": 25 }
]
}
Older calls: lookback
Speed.ai keeps about a week of calls ready. Asking for older ones returns 422 with the earliest date available and the exact start_time to re-fetch. Request a lookback (at most 25 days back, a few per hour), wait a few minutes, then repeat the original request. With no date_from, LawLink instead starts the window at the earliest call Speed.ai holds and says so in window_note.
The refusal
{ "detail": {
"message": "Speed.ai only has call history back to 2026-10-13T00:00:00Z for this window. …",
"reason": "speed_ai_history_not_available",
"earliest_available": "2026-10-13T00:00:00Z",
"lookback_start_time": "2026-10-01T00:00:00Z"
} }
Example: re-fetch every line back to that time
curl -X POST \
"https://app.lawlink.ai/api/v1/speed-ai/calls/lookback" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "start_time": "2026-10-01T00:00:00Z" }'
Example: one line, last 14 days
curl -X POST \
"https://app.lawlink.ai/api/v1/speed-ai/lines/12/lookback" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "days": 14 }'
Universal API and AI assistant
Calls also come through the platform-agnostic communications endpoint, normalised like every other platform's (direction, call_status, senders/receivers, plus agent_score, is_lead, rescue_call). Your AI assistant uses the call_intake tool — firm, lines, calls, call, recording, summary, missed_calls, lookback — and communications with platform=speed_ai.
Example: universal communications
curl -X GET \
"https://app.lawlink.ai/api/v1/universal/communications?platform_id=speed_ai&date_from=2026-10-19&query=4045551234" \
-H "Authorization: Bearer ACCESS_TOKEN"
Example: what to ask your assistant
# “Who called yesterday and was never called back?”
call_intake action="missed_calls" date_from="2026-10-19" time_zone="America/New_York"
# “Show me everything Jane Roe said when she called.”
call_intake action="calls" query="+1 404 555 1234" → call_intake action="call" call_id="9811"
Limits
Speed.ai allows 100 requests a minute per firm, shared by everyone at the firm. It keeps about one week of calls ready. Older calls, back to 25 days at most, must be refreshed with a lookback first.
⚠️ What this means for reports:
- Speed.ai can serve daily and weekly reports, but not monthly ones or month-over-month comparisons.
- If a request reaches past what is ready, LawLink says how far back calls are available and names the lookback to run. It never fills the gap with a guess.
- Speed.ai allows only a few lookbacks an hour. Calls appear a few minutes after one is requested.
Troubleshooting
"Speed.ai rejected the client ID / secret"
Check both values with your Speed.ai contact. If Speed.ai issued new credentials, reconnect with them.
Connected, but no calls
LawLink only sees lines it is set to read. Open the Speed.ai page and
choose a depth for each line. Calls from before that may need a lookback. An empty answer carries no_calls_note when this is the cause.
"Rate limit exhausted"
The firm's 100 requests a minute are used up. Wait a minute; prefer summaries over paging through every call.