> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wtocrm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send WhatsApp messages with WTOCRM API: curl and Node.js

> Send your first WhatsApp API message with curl or Node.js. See the REST endpoint, choose text, media or templates, and troubleshoot 401 and 429 responses.

**To send a WhatsApp message with WTOCRM, POST a recipient number and `textMessage.text` to `https://waapi.wtocrm.com/message/sendText/{instanceName}` with your `apikey` header.** The examples below use your backend and an already connected instance. No SDK is required.

Use this starting point when you are adding a customer update to a SaaS product or building a client's automation. First prove that one message reaches your own test phone. Then add attachments, callbacks and controlled retries.

> **Key takeaways**
>
> * Send text with a JSON POST to `/message/sendText/{instanceName}`; authenticate with `apikey`.
> * Create and connect an instance first. A QR or pairing code alone does not confirm a connection.
> * Media upload, approved business templates and `wa.me` links solve different tasks.
> * Fix credentials for 401; inspect the response and reduce request pressure for 429. Check ambiguous send outcomes before retrying.

![A backend module, translucent gateway and phone joined by one message route, illustrated conceptually](https://assets.wtocrm.com/blog/2026/send-whatsapp-message-api/cover-e5bfbefd61.webp)

Concept illustration of a backend sending a message through an API gateway to a phone; not a product screenshot.

## Send your first text message with curl or Node.js

Before running either example, [create an instance](https://docs.wtocrm.com/waapi/create-instance.md), [connect it by QR or pairing code](https://docs.wtocrm.com/waapi/connect-instance.md), and confirm `instance.state` is `open` using the [connection-state endpoint](https://docs.wtocrm.com/waapi/get-connection-state.md). These steps describe WTOCRM linked-device protocol access, separate from Meta's official WhatsApp Business Platform / Cloud API onboarding.

Use a terminal with curl, or Node.js 22 or later for the JavaScript example. Node provides [native `fetch`](https://nodejs.org/docs/latest-v22.x/api/globals.html#fetch). Keep credentials on your backend. Set these variables in the shell that runs the example, replacing all three placeholder values:

```bash theme={null}
export WTO_API_KEY='YOUR_API_KEY'
export WTO_INSTANCE='YOUR_CONNECTED_INSTANCE'
export WTO_TO='COUNTRY_CODE_AND_YOUR_TEST_NUMBER'
```

Use your own test recipient's WhatsApp number with its country code and digits only, without `+`, spaces or punctuation. The variables configure the examples; they do not create or connect an instance. For a deployed application, inject the key through your existing secret-management mechanism.

### curl: one POST request

The [text-message reference](https://docs.wtocrm.com/waapi/send-text-message.md) defines this request body:

```bash theme={null}
curl --request POST "https://waapi.wtocrm.com/message/sendText/${WTO_INSTANCE}" \
  --header "apikey: ${WTO_API_KEY}" \
  --header 'Content-Type: application/json' \
  --data "{\"number\":\"${WTO_TO}\",\"textMessage\":{\"text\":\"WTOCRM API test\"}}"
```

This is the minimal text send after setup. It sends a fixed test message. The reference documents HTTP `200` and a response with `key`, `message` and `status` fields. Inspect the actual response and check the receiving phone; an API result is not proof of final delivery.

### Node.js: native fetch, no SDK

Save this as `send-message.mjs`, then run `node send-message.mjs` from the configured shell:

```javascript theme={null}
const response = await fetch(`https://waapi.wtocrm.com/message/sendText/${encodeURIComponent(process.env.WTO_INSTANCE)}`, {
  method: 'POST',
  headers: { apikey: process.env.WTO_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({ number: process.env.WTO_TO, textMessage: { text: 'WTOCRM API test' } })
});
const body = await response.text();
if (!response.ok) throw new Error(`HTTP ${response.status}: ${body}`);
console.log(body);
```

`fetch` does not throw merely because the server returns 401 or 429. The explicit `response.ok` check turns those responses into errors you can handle. Keep the full response in a restricted development log when debugging; redact credentials, phone numbers and message contents before sharing logs.

## Understand the REST endpoint and URL

An endpoint identifies an operation by its HTTP method and URL. For WTOCRM text messages, use these parts together:

| Part | Value | Purpose |
| - | - | - |
| Method | `POST` | Submit a message operation |
| API base URL | `https://waapi.wtocrm.com` | Address the WTO WA API service |
| Path | `/message/sendText/{instanceName}` | Select text sending for one instance |
| Authentication | `apikey` request header | Supply a key authorized for that instance |
| JSON body | `number`, `textMessage.text` | Set the recipient and message |

Replace `{instanceName}`; do not send the braces literally. Use the instance name, not your recipient's phone number. Opening the URL in a browser usually sends a GET without the required header or JSON body, which does not perform this POST operation.

This URL and payload belong to WTOCRM. Do not combine them with another provider's bearer-token examples, Graph API paths or request schema. [WTOCRM](https://wtocrm.com) publishes this guide; the linked product references define the current request contracts.

**How we checked these examples:** On 3 November 2026, we checked the curl and Node.js snippets against a local HTTP mock using Node.js v24.22.2. The checks covered request paths, `apikey`, text JSON, multipart upload and Node handling for HTTP 200/401/429. They did not send live WhatsApp messages.

## Choose text, media or template messages

Choose the format based on the content and the channel you have connected, rather than changing the endpoint until a request succeeds.

| Type | Choose it for | WTOCRM reference | Check first |
| - | - | - | - |
| Text | A plain-text reply or test message | `/message/sendText/{instanceName}` | Connected instance and documented JSON fields |
| Media | A quotation PDF, image, video or audio attachment | `/message/sendMedia/{instanceName}` | File upload format and media type |
| Template | A business notification on a channel that requires approved message templates | `/message/sendTemplate/{instanceName}` | Channel support, template approval and the provider's required parameters |

### Upload media using multipart form data

The current [media-message reference](https://docs.wtocrm.com/waapi/send-media-message.md) requires `number`, `mediatype` and a binary `media` file. For a PDF that you supply as `quote.pdf` in your current directory:

```bash theme={null}
curl --request POST "https://waapi.wtocrm.com/message/sendMedia/${WTO_INSTANCE}" \
  --header "apikey: ${WTO_API_KEY}" \
  --form "number=${WTO_TO}" \
  --form 'mediatype=document' \
  --form 'media=@./quote.pdf;type=application/pdf'
```

Let curl set the multipart boundary. Do not reuse the text example's `Content-Type: application/json`. The documented media types are `image`, `video`, `audio` and `document`; optional `caption` and `fileName` fields are also available. The example uploads your local file; it does not assume that the `media` field accepts a remote URL.

### Confirm template support before implementation

An approved business template is different from a reusable text string in your application. Use templates when your selected business channel requires that approved message format for the notification you intend to send. A `wa.me` link and an ordinary text request do not replace template approval.

WTOCRM lists a [template-message endpoint](https://docs.wtocrm.com/waapi/send-template-message.md), but its current public request schema exposes `number` and `textMessage.text` without defining an approved template's name, language or component mapping. It also does not specify which connection modes support that operation. Confirm the exact channel and template payload before implementing it; changing `sendText` to `sendTemplate` is not a verified conversion.

If you are configuring WTOCRM's official Cloud API channel, follow its separate [WhatsApp channel setup](https://docs.wtocrm.com/user-guides/channels/whatsapp-setup.md). Do not assume that the QR-linked instance used for this text example has the same template workflow or capabilities.

## Distinguish three meanings of WhatsApp API link

“WhatsApp API link” can refer to three different destinations. Identify who opens the link and what action it should perform.

| Meaning | Example or destination | What it does |
| - | - | - |
| REST API endpoint | `https://waapi.wtocrm.com/message/sendText/{instanceName}` | Your backend submits a structured message request |
| Click-to-chat link | `https://wa.me/<international-number>?text=<encoded-text>` | A person opens a chat with optional prefilled text and chooses whether to send |
| Account or channel binding entry | WTOCRM connection guide or channel settings | An account holder links a device or authorizes the selected channel |

For a `wa.me` link, use the full international number without `+` or punctuation, and URL-encode the optional text. Such a link neither authenticates your backend nor automatically sends a message.

For device linking, `GET /instance/connect/{instanceName}` requests the QR or pairing information; the account holder still completes the phone step. A channel-binding link is an onboarding entry, not a universal sending URL. Keep login QR images and pairing codes private, and direct account holders through the documented connection flow.

## Troubleshoot 401 and 429 without duplicate sends

Start by capturing the HTTP status, response headers and response body. During diagnosis, add `--include` to the curl request above; in Node, inspect `response.status`, `response.headers` and `body`. Remove personal data before sharing a trace.

### 401: correct authentication before retrying

The WTOCRM text and media references define 401 as missing or invalid authentication. Check that `WTO_API_KEY` is set, the header is named `apikey`, and your key belongs to the target environment and is authorized for the requested instance. If you use a proxy, verify that it forwards this header.

A missing instance name is a separate routing problem. HTTP 403 means insufficient permissions in these references, while 404 can indicate an unknown instance. Repeatedly retrying the same unauthorized request will not repair any of these problems.

### 429: reduce pressure and follow the response

[HTTP 429](https://www.rfc-editor.org/rfc/rfc6585.html#section-4) means too many requests within a period. The standard allows a `Retry-After` header; it does not require one. If the service supplies it, respect the indicated wait. Otherwise use a capped backoff with jitter, a finite attempt count and a queue that limits concurrency.

The WTOCRM send references do not currently publish a 429 response contract or a fixed requests-per-second allowance. Treat this as general handling for a 429 returned by your actual API path, gateway or provider. Inspect the body and headers to identify the source; do not import another provider's numeric limits or assume retries will bypass an account restriction.

For an automation studio, coordinate workers that share the same account or service allowance. Independent workers retrying at once can keep the request pressure high. Retain the original job identity and stop retrying when the configured budget is exhausted.

### Separate bad input, timeouts and delivery issues

| Result | Next action |
| - | - |
| `400` | Compare the body, recipient format and media form fields with the relevant reference |
| `403` | Check the key's permissions; do not treat it as a transient rate limit |
| `404` | Check base URL, route and instance name |
| Timeout or lost response | Establish whether the send completed before submitting it again |
| Successful API response, no message on phone | Check connection state and available message events; record the actual outcome |

Do not assume the API provides an idempotency header: the current send references do not document one. Your application should record jobs and returned message identifiers where available, and reconcile uncertain outcomes before resending. A local job identifier alone cannot prevent a second send after an ambiguous network failure.

## Verify one message, then connect your workflow

A useful first test has three observations: the API response, the message on your test phone, and a reply reaching your application. Use the [webhook configuration reference](https://docs.wtocrm.com/waapi/set-webhook.md) to configure events supported by your instance, then associate the callback with the correct instance and contact.

Send only messages your recipients have agreed to receive. Keep connection failures separate from authentication failures, and verify your retry behavior before adding more workers or customers.

**Open the [WTOCRM API connection guide](https://docs.wtocrm.com/waapi/connect-instance.md)** to connect your instance, confirm `open`, and run your first text-message request.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.