Skip to the page

Get started

Limits

Every cap BlueBot has, why it's there and what happens when you reach it. Most of them hold a text until it can go rather than refuse it.

BlueBot sends from your own number through your own Mac, so its limits are there to keep that number in good standing with Apple and the carriers, and to keep one runaway loop from becoming a problem. They come in two kinds:

  • Sending rules are yours. Pace, new people per day, quiet hours and expiry each have a default you can change in Settings → Sending rules or with PATCH/v1/settings.
  • Fixed limits are the same for every account: the daily ceiling, sizes, the API's rate limit and how long things are kept.

Almost nothing here refuses a send. A text that can't go yet is accepted and waits with a hold that says why and until when, then goes on its own. The few limits that do refuse a request answer with an error code before anything is queued, so nothing is half done.

Every limit

LimitValueWhyWhen you reach itA setting?
Texts per day1,000 per accountOne person’s business never needs more, and a number that sends more than this looks like a bulk sender to Apple.Texts over it wait with platform_daily_limit until midnight in your zone, and you get one email.No
New people per day50 by defaultApple flags accounts that message many strangers. Texts to people already in a conversation don’t count.Texts to new people wait with daily_new_people_limit until midnight. Raise it in Settings; the dashboard warns above 200.Yes
Pace20 seconds between texts (5 to 300)A person types one text at a time; a Mac that fires 50 in a second looks like a bot.Texts queue in order with pacing and an estimated until.Yes
Quiet hours9:00 PM to 8:00 AM in your zone, on by defaultTexts at 3 AM earn STOP replies.Texts wait with quiet_hours until they end.Yes
Expiry24 hours by default; any time you set per text“Your table is ready” is wrong a day later. A text that can’t go in time shouldn’t go late.A text still waiting at expires_at becomes expired and fires message.expired.Yes
Text length2,000 charactersLong texts are split by carriers when they fall back to SMS, and read badly as iMessage.The send is refused with invalid_request.No
Files25 MB each, 10 per textMessages handles big files slowly, and SMS can’t carry them at all.The upload is refused with payload_too_large.No
Metadata20 keys, 500 characters a valueIt’s sent with every event for the text, so it’s meant for ids rather than documents.The send is refused with invalid_request.No
API requests120 a minute per keyKeeps one runaway loop from slowing everyone. Sends that can’t go yet are held, never refused with a 429.rate_limited (429) with retry_after. Every answer carries RateLimit-* headers.No
Idempotency keyskept 24 hoursThat covers any retry without holding a key forever.After 24 hours the same key is treated as new.No
API keys10 live per accountOne per app or person is plenty; more is usually keys nobody revoked.limit_reached until you revoke one.No
Broadcast size500 recipientsBroadcasts are for people who asked to hear from you, and the Mac sends them at your pace.The broadcast is refused with limit_reached.No
Words kept30 daysThe words of a text are the private part, so BlueBot deletes them first.30 days after a text went or came, its text and files are deleted, as are a finished broadcast’s words; the facts (who, when, state) stay.No
Events kept30 daysLong enough to catch up after an outage on your side.GET /v1/events reads back 30 days.No
Webhook retriesabout 72 hoursCovers a weekend outage on your side.After 72 hours of failures the webhook is paused and you get one email. Nothing is dropped silently.No
Lookupsanswered within 15 secondsThe answer comes from your Mac, which may be busy or away.After 15 seconds the answer is service: "unknown" with basis: "timeout" or "device_offline".No

Limits that hold a text

These four never cause an error. The text is answered 201, comes back queued with a hold, and goes by itself when the hold clears, unless its expires_at passes first.

Limithold.reasonIt clears
Texts per day (1,000)platform_daily_limitAt midnight in your time zone.
New people per day (50 by default)daily_new_people_limitAt midnight in your time zone, or when you raise the setting.
Pace (20 seconds by default)pacingAt the text's slot. hold.until is the estimate.
Quiet hours (9:00 PM to 8:00 AM by default)quiet_hoursWhen quiet hours end.

Here is how they add up. Dana runs a small cleaning company and sends 120 texts at 2:00 PM to remind clients of next week's visits. 80 of the clients have never texted with her through BlueBot.

  • Only 50 of the 80 new people can be texted today. The other 30 wait with daily_new_people_limit until midnight. Midnight is inside her quiet hours, so at midnight their hold becomes quiet_hours, and they go from 8:00 AM.
  • The 90 that can go today leave her Mac 20 seconds apart, so the last of them goes about 30 minutes after the first. While they wait their turn, their hold is pacing.
  • The 30 held overnight still have until 2:00 PM tomorrow before their 24-hour expiry, so they go in time.
  • None of this needs a retry. Her loop sent 120 requests, got 120 answers and is done.

A text to someone you already have a conversation with never counts against new people, so a reply to a client who texted you a minute ago goes at once (after the pace).

Limits that refuse a request

These answer with an error and queue nothing. Fix the request and send it again.

LimitValueYou get
Words in one text2,000 charactersinvalid_request (400), with details naming text
One file25 MBpayload_too_large (413)
Files on one text10invalid_request (400)
Metadata20 keys, names up to 40 characters, values up to 500invalid_request (400)
A JSON body1 MBpayload_too_large (413)
Requests per key120 a minuterate_limited (429) with Retry-After
API keys per account10limit_reached (409)
People in one broadcast500limit_reached (409)

The rate limit counts requests, not texts. A send that goes through but is held still counts as one request, and reading a message back counts as one too. If you poll for state, poll slowly or use webhooks instead. Every answer carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset, so a program can slow down before it's refused. Rate limits has the details.

Limits on time

WhatHow longWhat happens after
A queued text24 hours after it was due, unless you set expires_atIt becomes expired and message.expired fires. It never goes.
An Idempotency-Key24 hoursThe same key is treated as new.
The words and files of a text30 daysThey're deleted. The message's facts stay. Data retention
Events (GET /v1/events)30 daysOlder events are gone from the feed.
Webhook retriesAbout 72 hoursThe webhook is paused and you get one email. Retries
A file's urlAn hourAsk GET/v1/files/{id} for a fresh one.
A lookupUp to 15 secondsThe answer is service: "unknown" with basis: "timeout".
A file you upload and never sendA dayIt's deleted.

The expiry setting runs from 1 to 168 hours (a week). Per text, expires_at can be any time after the text is due.

See where you stand

GET/v1/device answers today's counts against the daily limits, and how many texts are waiting:

GET/v1/deviceGet the Mac →
curl "https://usebluebot.com/api/v1/device" \
  -H "Authorization: Bearer $BLUEBOT_API_KEY"
Response200The part of the answer about limits
{
  "object": "device",
  "status": "online",
  "held_count": 2,
  "queued_count": 5,
  "today": {
    "sent": 14,
    "new_people": 3,
    "new_people_limit": 50,
    "daily_limit": 1000,
    "resets_at": "2026-11-14T05:00:00.000Z"
  }
}
You gotIt meansDo next
today.new_people equal to today.new_people_limitTexts to anyone new wait until resets_at. Texts to people you already talk with still go.Wait, or raise new_people_per_day if you know these people asked to hear from you.
today.sent equal to today.daily_limitEvery text waits until resets_at. You got one email about it.Wait. The ceiling isn't a setting.
held_count above 0Some queued texts are waiting on a hold.List them with GET /v1/messages?state=queued and read each hold.

resets_at is the next midnight in your account's time zone, written in UTC. Today's counts start again then.

Why the daily ceiling isn't a setting

1,000 texts a day is far more than one person's business sends, and a number that sends more than that looks like a bulk sender to Apple, whatever the reason. BlueBot is for texting people who know you. If you need to text thousands of people a day, a hosted service with its own numbers is the better tool, as What BlueBot is not explains.

The new-people setting is yours, from 0 to 1,000. The dashboard warns above 100, because Apple flags accounts that message many strangers, and once an account is flagged no setting brings it back.