Most teams don't need a new texting tool. They need the tools they already run (the CRM, the website, the ERP, the automation canvas) to send a text when something happens. That can be a booked demo, a shipped order, a form fill or an overdue invoice.

You can connect texting to those tools in three ways: a native integration, a webhook from the tool to an SMS API, or a no-code automation layer in between. Each one fails in a different way. This post walks through all three for HubSpot, Zoho CRM, n8n, WordPress and Odoo. It shows the actual API call, the cost math, and the compliance pieces that break most often once a workflow goes live.

Three ways to wire texting in

ApproachWhat it looks likeGood forWhere it breaks
Native integrationAn app from the marketplace, set up with OAuth, that syncs messages both waysTeams that want replies inside the CRM recordOnly exists for some tool and provider pairs. You're limited to what the vendor built
Webhook / custom codeThe tool's workflow calls the SMS API directlyTransactional texts with clear triggersYou own retries, opt-out sync and error handling
No-code layer (n8n, Zapier, Make)The trigger fires in tool A, n8n calls the SMS API, results are written backMulti-step logic and tools without webhooksOne more system to monitor. Task limits on hosted plans

The honest default is to use a native integration when one exists and does what you need. On our side, Ready's deepest native integration is GoHighLevel. It connects over OAuth, syncs inbound and outbound messages both ways, and maps each GHL location to its own sub-account. For HubSpot and Zoho CRM, check Other apps under Settings → Integrations first. With HubSpot, an automation can text a contact when it appears in HubSpot, update the contact, add a note or move a deal; with Zoho CRM it can create a lead. Neither needs code. For n8n, WordPress and Odoo, or anything the apps under Settings → Integrations don't cover, call Ready's REST API from the tool's own workflow engine or through n8n.

If you're still deciding whether texting should live inside the CRM at all, CRM with SMS: built-in texting vs integrating a provider covers that choice.

The one API call everything below uses

Every integration in this post ends up making the same request:

POST https://api.tryready.com/v1/messages
X-API-Key: <your key>
Idempotency-Key: 6f1c2b9e-1d4a-4c3f-9a7e-2b8d5e0c7a11
Content-Type: application/json

{
  "to": "+12125550199",
  "body": "Hi Dana, your demo is confirmed for Thursday at 2 PM ET. Reply STOP to opt out.",
  "consent_attested": true
}

Three details matter here.

  • Idempotency-Key must be generated once per intended message and reused on retries. Workflow engines retry failed HTTP steps. Without this header, a timeout followed by a retry can send the same text twice. If you generate a fresh UUID on every attempt, you lose the protection.
  • consent_attested is your promise that the recipient agreed to receive texts. Ready records that attestation per send: who sent it, to how many people, and when. Ready does not store the recipient's opt-in time, wording or page URL. Your CRM or form tool keeps that record, so make sure it does. (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.)
  • from_strategy (local, even or random) is optional. local picks the account's number closest to the contact's area code.

For lists, POST /v1/messages/bulk takes up to 100 recipients per call, so split larger lists into batches. Full reference: docs.tryready.com/api/messages and docs.tryready.com/api/bulk-messages.

Tool by tool

HubSpot

HubSpot has its own SMS on some Marketing Hub tiers. If that's included in your plan and covers your use case, keep using it. For a separate API provider, the usual route is a workflow action. On the HubSpot tiers that include webhook and custom-code workflow actions, a "Send a webhook" step or a small Node.js custom code action can call /v1/messages with the contact's phone property.

Two practical notes:

  • Normalize phone numbers to E.164 before the call. A 10-digit US number is treated as +1, but HubSpot phone fields often hold free text like "(212) 555-0199 ext 4".
  • Put the idempotency key in a contact or deal property set earlier in the workflow, so a retried step reuses it.

There's more on HubSpot-specific options in HubSpot SMS: native options, integrations, and dialer choices.

Zoho CRM

Zoho workflow rules can fire a webhook. Custom headers like X-API-Key are easier to control from a Deluge function, though. A function attached to the workflow builds a header map and calls invokeurl with a POST to /v1/messages. Deluge also lets you skip the send when the mobile field is empty, which a raw webhook can't do.

Zoho is a good fit for appointment confirmations and stage-change texts. Each record change is one clear trigger, so it maps to one message.

n8n

n8n is the most flexible option and the one we'd reach for when the source tool has no usable webhook, or when the logic has branches. The pattern looks like this:

  1. Trigger node (a webhook, a schedule, or a HubSpot, Zoho or Odoo node).
  2. Code node that formats the number and generates the idempotency key with crypto.randomUUID(). Because the key is created here, before the HTTP step, retries of the HTTP step reuse it.
  3. HTTP Request node: POST to https://api.tryready.com/v1/messages with the X-API-Key and Idempotency-Key headers.
  4. A write-back node that stores the result on the CRM record.

For lists, use a Split In Batches node set to 100 and post to /v1/messages/bulk. Keep throughput in mind: a fresh standard 10DLC campaign typically moves somewhere around 1 to 4 segments per second, so a large send drains over minutes, not instantly. For more on no-code patterns, see SMS automation with Airtable, Brevo and no-code tools.

WordPress

WordPress has no workflow engine, so you have two options:

  • A form plugin's webhook feature that sends submissions to n8n, which then calls the API.
  • A few lines of PHP on a form-submission hook, using wp_remote_post() with the API headers and wp_generate_uuid4() for the idempotency key. Keep the API key in wp-config.php, not in the theme.

One WordPress-specific trap is that WordPress turns straight quotes into curly ones and -- into long dashes. On most providers, a curly apostrophe pushes the whole message into unicode, which allows only 70 characters per segment. Ready swaps curly quotes, long dashes and ellipses for plain ones before sending, so they don't change the segment count. Emoji still do.

Only text people who ticked a consent box on the form. A contact form submission on its own is not consent to texts.

Odoo

Odoo ships its own SMS through in-app purchase credits. For basic transactional texts on Odoo Online, that may be all you need. If you want a separate API provider, the realistic routes depend on hosting:

  • Recent versions let automation rules send a webhook. Point it at n8n, and n8n calls Ready.
  • Self-hosted Odoo can use a small custom module that makes the HTTP call directly. Sandboxed server actions often can't make outbound requests.

Invoice reminders and delivery notices are the common Odoo triggers. Both are single-segment, transactional texts.

The parts that break in production

Getting the first text out is easy. These are the problems that show up in month two.

Opt-outs that don't flow back

Ready handles STOP and UNSUBSCRIBE automatically. The opt-out applies across campaigns, and later sends to that number are refused up front without being charged. Your CRM doesn't know any of this unless you tell it, so marketers will keep enrolling that contact in workflows. Run a nightly n8n job against GET /v1/opt-outs (or GET /v1/opt-outs/:phone per contact) and set a "do not text" property in HubSpot, Zoho or Odoo. That list holds only this account's opted-out contacts, so check GET /v1/opt-outs/:phone before another tool texts a number.

Quiet hours

A workflow that fires at 11 PM, because someone booked late, will try to text at 11 PM. An API text in the recipient's quiet hours is held only if sending opens within about 6 hours, and you're charged only when it goes out; a text at 11 PM is refused with 409 QUIET_HOURS_BLOCK, so have the workflow wait until next_allowed_at and send again. Campaigns, drip campaigns and automations wait up to 24 hours for the window. That reduces risk, but it doesn't remove it. Compliance stays the sender's responsibility.

Registration

Unregistered traffic gets filtered by carriers. Ready handles brand and campaign registration in-app, and most approvals take 2 to 7 days. There's no setup fee. You pay $25 at submit for the first month, then the monthly cost is $25 for registration + $2 per number. An account can send up to 500 texts a month before it registers. Pick the use case that matches what your integration actually sends. Reminders registered as marketing (or the reverse) cause trouble. The 10DLC explainer covers the basics.

Replies

Inbound replies land in the Ready inbox, which matters if a customer answers "can we move it to 3?". Replies are billed like sent texts. If you want them on the CRM record too, Ready's webhooks can forward them. The event formats are in the webhooks docs.

What it costs: two worked examples

Ready's Standard rate is $0.0075 per segment, plus a $0.0045 carrier fee, for each segment sent or received.

Example 1: Zoho appointment reminders. Assumptions:

  • 3,000 reminders a month, each under 160 plain characters, so 1 segment each.
  • About 20% of recipients reply once, which adds 600 inbound segments.

The math:

  • Messages: 3,600 segments × ($0.0075 + $0.0045) = $43.20 at today's carrier fee.
  • Registration for one number: $27 a month.
  • Total: about $123.20 a month.
  • Optional: turning on TCPA/DNC scrubbing adds $0.003 × 3,000 outbound segments = $9.

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.

Example 2: the emoji tax in an n8n promo. Assumptions:

  • A 150-character promo sent to 2,000 opted-in contacts.
  • First version is plain GSM text. Second version is the same text with one 🎉 added.

The math:

  • Plain text: 1 segment each, so 2,000 × $0.012 = $24.
  • With one emoji: 150 characters at 67 per multipart unicode segment is 3 segments each. That's 6,000 segments, or $147.

The emoji costs about 3x as much. If your integration lets marketers write free text, add a character and segment check before the HTTP step.

On price comparisons: Twilio's list rate is around $0.0083 per segment, and GoHighLevel's LC Phone is around $0.0128 all-in. If you have engineers who want raw CPaaS and will build registration, opt-out storage and quiet-hour logic themselves, that's a reasonable choice. What Ready adds is that work already done: self-serve registration, automatic STOP handling, quiet hours, scrubbing, and an inbox where replies land.

Which route to pick

  • A native integration or an app under Settings → Integrations covers your use case? Use it.
  • One clear trigger, one message (a reminder, a confirmation, a shipping notice)? Call the API from the tool's own workflow: HubSpot custom code, a Zoho Deluge function, or PHP in WordPress.
  • Branching logic, several tools, or no webhooks at all? Put n8n in the middle.

Whichever route you choose, build three things on day one: a reused idempotency key, a nightly opt-out sync back to the CRM, and a segment check on any message a human writes. For other CRMs like Pipedrive and Salesforce, the same patterns apply. See SMS integrations for CRMs.

To test the wiring, sign up and add a card. The first 20 texts are free one-to-one sends, so use them to check your HubSpot or n8n flow end to end before you pay for registration. Free texts end once a registration is paid for. When you're ready to register, the app walks you through it.