Most ops teams don't need an SMS "platform migration." They need one thing: when a row in Airtable changes, or a contact hits a step in Brevo, a text goes out. You can wire that in an afternoon with Zapier, Make, n8n or an Airtable automation script. The send is easy. The parts that cause trouble come later: the duplicate text, the 11 PM text and the contact who opted out last month but still has a ticked checkbox in your base.
Every no-code send follows the same pattern. A trigger fires, a filter decides whether this record should get a text, and one HTTP request sends it. This guide walks through that pattern for Airtable and Brevo, shows the exact request, and covers the consent traps that no-code stacks create by default.
The pattern behind every no-code text
Strip away the tool names and every automation has three steps:
- Trigger. A record enters a view, a field changes, a form is submitted, or a contact reaches a step in an email automation.
- Filter. Should this record get a text right now? Check consent, opt-out status, a phone number in a usable format, and whether you've already sent this message.
- Send. One
POSTto a messaging API.
Teams usually build step 1 and step 3 and skip step 2. Every trap later in this post lives in step 2.
The send itself, on Ready, is one request to POST /v1/messages:
POST https://api.tryready.com/v1/messages
X-API-Key: <your key>
Idempotency-Key: 3f6c2a9e-8d41-4b7a-9c55-1e2f0a7b6d13
Content-Type: application/json
{"to": "+12125550199", "body": "Hi Dana, your install is confirmed for Tue 10 AM. Reply STOP to opt out.", "consent_attested": true} to is E.164. A bare 10-digit US number is treated as +1, which helps when your Airtable phone field is messy. consent_attested is your promise that this recipient agreed to texts. Treat it that way, not as a field you hardcode to true and forget. The full reference is at docs.tryready.com/api/messages, and the quickstart covers getting a key.
Airtable: two ways to send
Option A: an Airtable automation with a script step
Airtable automations can run a script, and scripts can make outbound HTTP requests. That means you can send without a middleman:
const cfg = input.config(); // phone, message, sendKey passed in from the trigger record
const res = await fetch("https://api.tryready.com/v1/messages", {
method: "POST",
headers: {
"X-API-Key": cfg.apiKey,
"Idempotency-Key": cfg.sendKey,
"Content-Type": "application/json"
},
body: JSON.stringify({ to: cfg.phone, body: cfg.message, consent_attested: true })
});
output.set("status", res.status); Write the returned status back into a field on the record ("SMS status: 200" or the error code). That gives you an audit column and a way to filter failed sends into a retry view.
Tradeoff: anyone who can edit the automation can see the input values. If the API key sits in a script input, treat base editors as people who hold your SMS key.
Option B: Zapier, Make or n8n
Use the "record enters view" or "record updated" trigger and a filter step, then the Ready app's Send SMS action in Zapier (sign in once, no API key to paste). In Make or n8n, use an HTTP action that sends the same JSON. This adds a tool and a per-task cost, but it also gives you retries, run history and branching without writing code. For a team where nobody wants to own a script, that's a fair trade.
If your contacts live in a CRM rather than a base, the same approach applies. We cover the CRM-side options in SMS integrations for CRMs.
Sending the same text to many rows
If 300 records need an identical message, such as a site-closure notice to everyone with an open job, use POST /v1/messages/bulk with a to array. It takes at most 100 recipients per call, so 300 records means 3 calls. Personalized bodies (first name, appointment time) need one /v1/messages call per record. Details are at docs.tryready.com/api/bulk-messages.
Brevo and other email-first tools
Brevo has its own SMS channel. If you already run email there and send a handful of SMS marketing campaigns a month, the native channel is probably fine, and adding an API hop just to move texting elsewhere isn't worth it.
Teams usually route Brevo events out to a separate SMS API for two reasons:
- They want texts and replies in one two-way inbox alongside other channels, with replies landing somewhere a person actually reads.
- They want the same send path for Brevo-triggered texts as for texts triggered from Airtable, forms and the product. That means one opt-out list, one registration and one bill.
The wiring: if your Brevo automation builder offers a webhook step, point it at a Zapier or Make catch hook, or at your own small endpoint, and make the /v1/messages call from there. If it doesn't, trigger off the Brevo contact or list change in Zapier or Make directly. The same pattern works for form tools. See connecting SMS to Mailchimp, Typeform, Calendly and Jotform.
Double sends: the most common no-code bug
No-code triggers fire more often than you'd expect:
- "Record updated" fires on any edit, so fixing a typo in the address re-sends the confirmation.
- A record that leaves a view and re-enters it triggers again.
- Zapier and Make retry failed or timed-out steps, and a timeout doesn't always mean the first request failed.
There are two fixes, and you want both:
- Store a send key per message. Generate a UUID into a field like
confirm_send_keywhen the record is created, and pass it as theIdempotency-Keyheader. A retried request with the same key won't send twice. - Mark the record as sent and filter on it. A
confirm_sent_attimestamp written after a successful call, plus a filter of "only if empty," stops the edit-retrigger problem the idempotency key alone doesn't cover.
The consent traps
This is where no-code stacks get companies into trouble. The tools make it easy to text anyone with a phone number, and a phone number is not consent.
1. The checkbox isn't the consent record. An "SMS opt-in ✓" column says nothing about when, where or what wording the person agreed to. Ready records your attestation for each bulk send and each API send that sets consent_attested: who sent, to how many and when. It does not store the recipient's opt-in time, wording or page URL. Your base or form tool has to keep that. Add columns for opt-in timestamp, source form and the consent text version, and fill them at capture, not later. (A contact who signs up on a Ready-hosted opt-in page is the exception: Ready stores that sign-up, with the time, IP address and exact wording, and support@tryready.com can send you a copy.)
2. Imported lists inherit the checkbox. Someone pastes in 2,000 trade-show contacts and the default value of the opt-in field is true. Set the default to empty and require the source column before the filter passes. Cold contacts get a call or a letter. Texts go to people who opted in or who replied to you first.
3. Opt-outs happen outside your base. A contact replies STOP and Ready honors it immediately. The opted-out number is refused up front on every future send, and you aren't charged for the refusal. Your Airtable record still says "opted in," though, so your reports and other channels are wrong. Pull opt-outs back with GET /v1/opt-outs on a schedule, or check GET /v1/opt-outs/:phone in the filter step, and write the result to the record. That list holds only this account's opted-out contacts, so check GET /v1/opt-outs/:phone before another tool texts a number.
4. Automations ignore the clock. A batch import at 10 PM fires every trigger at 10 PM. Ready enforces quiet hours based on the recipient's area. An API text is held only if sending opens within about 6 hours, and it's charged only when it sends; a 10 PM batch is refused with 409 QUIET_HOURS_BLOCK, so route 409s into a retry view and resend after next_allowed_at. Don't build workflows that rely on a hold. Time-sensitive texts like "your tech is 20 minutes out" shouldn't land the next morning. Campaigns, drip campaigns and automations wait up to 24 hours for the window.
5. Registration must match what you actually send. A workflow that started as appointment reminders tends to grow promo texts. If your 10DLC campaign was registered for one use case and you send another, expect filtering. See matching use case to what you send. Advocacy, political and fundraising texts need written approval from us before the first send: email support@tryready.com and wait for our reply.
6. Litigator and landline exposure. TCPA damages run roughly $500 to $1,500 per text, which is why some teams turn on scrubbing for automated sends. Scrubbing and landline validation are off by default. When you switch them on for an account, each adds $0.003 per segment. The standalone TCPA & DNC litigator scrub is $0.005 per contact if you'd rather clean a list once before it enters the base. None of this makes you lawsuit-proof. It reduces risk, and compliance stays the sender's responsibility.
What the automation costs
The Standard rate is $0.0075 per segment plus a $0.0045 carrier fee. Replies you receive are billed the same way.
Worked example (assumptions stated): a field-service team sends 2,000 appointment confirmations a month from Airtable. Each is 140 plain characters, so 1 segment. Assume roughly 30% of recipients reply with a one-segment answer.
- Outbound: 2,000 × 1 segment × $0.0075 = $15 plus 2,000 × $0.0045
- Replies: 600 × 1 segment × $0.0075 = $5 plus 600 × $0.0045
- Total: $20 plus 2,600 × $0.0045 in carrier fees, before any scrub or validation surcharge
The formula-field trap: Airtable formulas that concatenate notes fields can quietly produce 175-character messages. Add one emoji and the text switches to unicode, which allows 67 characters per segment once it's multipart, so 175 characters becomes 3 segments. The same 2,000 sends then cost 2,000 × 3 × ($0.0075 + $0.0045), triple the outbound line. Add a LEN() check in the filter step. Curly quotes and long dashes pasted from docs don't matter on Ready, because we swap them for plain ones before sending. Emoji are different and still change the count.
Ready's all-in prices per segment include the carrier fee but not screening: Scrub lists and Number validation, the two switches in Settings under Compliance, each add $0.003 per segment when switched on, shown as screening on your bill, and both are off by default. Unless you turn the opt-out footer off, the first text to each contact, and one again from time to time, also gets "Reply STOP to opt out" and your business name if the message does not already have them, so a text close to the segment limit can bill one more segment.
On registration: an account can send up to 500 texts a month before it registers, and after that it has to register. The charge at submit is the first month, $25. The ongoing monthly cost is $25/mo for registration and $2 per number. Most approvals take 2 to 7 days. The first 20 texts are free one-to-one sends, so use them to test your Airtable script before you register. To send, you add a card and get a number, which is $2 a month with the first month charged when you get it.
When a no-code stack is the wrong tool
Be honest about the ceiling. Zapier-style flows work well for event-driven, one-to-one texts: confirmations, status updates, internal alerts. They get fragile for multi-step drip campaigns with branching on replies, and for anything that needs a person reading and answering replies quickly. At that point you want a real inbox and real automations. Our guide on triggered workflows to build first covers which ones belong in a proper automation builder rather than a chain of Zaps.
If you're a platform texting on behalf of your own customers, the move past no-code is the full API with sub-accounts, so each customer has its own numbers and registration. If an AI agent drives your ops, the MCP server exposes sending and contacts directly.
The practical takeaway
Build the filter step before the send step. Store consent details in your base, generate an idempotency key per message, mark records as sent, sync opt-outs back, and check message length before an emoji triples your bill. The send is one POST. If you want to try it, create an account, test with your 20 free one-to-one texts, then register before you scale up.