Skip to main content

How rate limits and fair usage work

The Sally API has two different limits, and they need two different reactions: rate limits protect the service from too many requests, the fair-usage policy governs how much you can transcribe.

This page shows how to read the limits of your company account, how to tell the three kinds of 429 apart and a retry loop with a growing pause that you can copy. The examples work as they stand once SALLY_TOKEN and DIRECTORY_ID are set, see the Quickstart.

Quick navigation

  1. Rate limits
  2. Read your limits
  3. Fair usage for transcription
  4. How to react
  5. Retry with backoff

1. Rate limits​

Requests are limited per token, and unauthenticated requests per client IP. Each company account has its own limits on top. When a limit is exceeded, the API answers 429.

LimitApplies toWhere you see the value
Per tokenEvery authenticated requestNot published
Per client IPRequests without a tokenNot published
Per company account, per minuteAll requests for one company accountmaxApiRequestsPerMinute
Per company account, per dayAll requests for one company accountmaxApiRequestsPerDay

2. Read your limits​

You can read the limits of a company account from the company account itself. With field selection the answer carries only what you need:

curl "https://api.sally.io/v1.0/directories/$DIRECTORY_ID?fields=name,maxApiRequestsPerMinute,maxApiRequestsPerDay" \
-H "Authorization: Bearer $SALLY_TOKEN"
200 OK
{
"name": "Example GmbH",
"maxApiRequestsPerMinute": 60,
"maxApiRequestsPerDay": 10000
}
FieldTypeMeaning
maxApiRequestsPerMinutenumberMaximum number of API requests per minute allowed for this company account.
maxApiRequestsPerDaynumberMaximum number of API requests per day allowed for this company account.

The values above are examples. Read the real ones for your company account, and read them again from time to time instead of hard-coding them. GET /v1.0/directories returns the same fields for every company account your token can address.

Reference: GET/v1.0/directories/{directoryId}

Recommendation

Spread your calls instead of sending them in bursts. With maxApiRequestsPerMinute at 60, one request per second stays below the limit, as long as nothing else uses the same company account at the same time.

3. Fair usage for transcription​

Uploads for transcription are additionally governed by a fair-usage policy. It applies the same way to the two-step upload and to the import from a URL. The API reports it with its own codes in the error body:

codeMeaningWhen it comes
FUP_LIMIT_EXCEEDEDThe transcription quota is used up.Already when you request an upload, before you send any file.
TOO_MANY_CONCURRENT_TRANSCRIPTIONSToo many transcriptions of your company account are running at the same time.For example when you finalize an upload.
429 Too Many Requests
{
"statusCode": 429,
"message": "<human-readable text>",
"code": "FUP_LIMIT_EXCEEDED"
}

The endpoints that start a transcription:

4. How to react​

Important

Handle the cases separately. A plain 429 means slow down and retry later. TOO_MANY_CONCURRENT_TRANSCRIPTIONS means wait until running transcriptions have finished. FUP_LIMIT_EXCEEDED means the quota is used up, and retrying soon will only produce the same answer. The error body is described in Errors.

429 withMeaningReaction
no codeRate limit exceededWait, then retry with a growing pause.
TOO_MANY_CONCURRENT_TRANSCRIPTIONSToo many transcriptions runningWait until running transcriptions have finished, then retry.
FUP_LIMIT_EXCEEDEDQuota used upDo not retry soon. Stop uploads and tell a person.

5. Retry with backoff​

A 429 does not tell you how long to wait, so wait a little longer after each attempt: one second, then two, four and so on, capped at one minute, with a small random share so that several clients do not retry in lockstep. The same loop fits a 500. FUP_LIMIT_EXCEEDED is passed through at once.

wait=1
for attempt in 1 2 3 4 5 6; do
response=$(curl -s -w '\n%{http_code}' \
"https://api.sally.io/v1.0/directories/$DIRECTORY_ID/recordings" \
-H "Authorization: Bearer $SALLY_TOKEN")
status=$(echo "$response" | tail -n 1)
body=$(echo "$response" | sed '$d')

if [ "$status" = "429" ] && [ "$(echo "$body" | jq -r '.code')" = "FUP_LIMIT_EXCEEDED" ]; then
echo "Quota used up, not retrying" >&2; break
fi
if [ "$status" != "429" ] && [ "$status" -lt 500 ]; then
echo "$body"; break
fi
sleep "$wait"
wait=$(( wait * 2 > 60 ? 60 : wait * 2 ))
done
Note

For TOO_MANY_CONCURRENT_TRANSCRIPTIONS a pause of a few seconds is often too short. Wait until your running transcriptions report isTranscriptionCompleted, or use a webhook, before you finalize the next upload.