SMS Quickstart

The fastest way to get started with ClickSend API in your preferred coding language.

This guide is for the current version of the Node.js SDK.

Send your first SMS with the official clicksend npm package in under 5 minutes.

This guide covers the current v2 SDK (clicksend, built on axios). If you're upgrading from the legacy @clicksend/clicksend-nodejs package, see the migration guide instead.

1. Prerequisites

Before you start, make sure you have:

Requirement

Details

A ClickSend account

Sign up free if you don't have one. New accounts get free credit to test with.

API credentials

Your username and API key, both on the API Credentials page of the dashboard. You'll authenticate with these, not your dashboard login password.

Node.js 14 or newer

Check with node -v. TypeScript is optional — the package ships plain JS + .d.ts types, so it works from a .ts or a plain .js file.

Account credit

Sending SMS consumes credit. Free trial credit is enough for this guide; top up on the Billing page if you get an INSUFFICIENT_CREDIT error later.

2. Install

Install the SDK with your package manager of choice:

npm install clicksend

# yarn
yarn add clicksend

# pnpm
pnpm add clicksend

3. Configure the client

Every API class in the SDK authenticates with HTTP Basic auth, using a Configuration object built from your ClickSend username and API key (not a bearer token). Never hard-code real credentials — load them from environment variables:

export CLICKSEND_USERNAME="your-clicksend-username"
export CLICKSEND_API_KEY="your-clicksend-api-key"

import { Configuration, SmsApi } from 'clicksend';

const configuration = new Configuration({
  username: process.env.CLICKSEND_USERNAME, // placeholder: your ClickSend username
  password: process.env.CLICKSEND_API_KEY,  // placeholder: your ClickSend API key
});

const smsApi = new SmsApi(configuration);

That's it — smsApi is now an authenticated client for every SMS endpoint (send, history, templates, delivery receipts, etc.). Each ClickSend resource has its own API class (MmsApi, ManagementApi, ContactsApi, ...); construct one per resource you need, reusing the same configuration.

4. Send your first SMS

This is a complete, runnable example. Save it as send-sms.ts (or .js, dropping the types), set the two environment variables from step 3, replace the to number with a real one, and run it.

import { Configuration, SmsApi } from 'clicksend';

async function main() {
  const configuration = new Configuration({
    username: process.env.CLICKSEND_USERNAME,
    password: process.env.CLICKSEND_API_KEY,
  });

  const smsApi = new SmsApi(configuration);

  const { data } = await smsApi.sendSms({
    sendSmsRequest: {
      messages: [
        {
          source: 'sdk',
          from: 'YOUR_SENDER_ID',        // placeholder: e.g. a ClickSend number, or omit to use your default sender
          body: 'Hello from ClickSend!',
          to: '+61411111111',            // placeholder: recipient in E.164 format
        },
      ],
    },
  });

  console.log(data);
}

main().catch((error) => {
  console.error('Failed to send SMS:', error.message);
  process.exit(1);
});

Run it:

npx tsx send-sms.ts      # TypeScript, no build step
# or: node send-sms.js   # if you dropped the types

Field names inside the request body are snake_case, not camelCase (from_email, list_id, etc. — to/from/body/source are single words so they look the same either way). Only the outer { sendSmsRequest: ... } wrapper key is camelCase. Getting this wrong doesn't throw — the server just silently ignores the misspelled field.

5. Understand the response

smsApi.sendSms(...) resolves to an axios response; the ClickSend payload is on .data. It looks like this:

{
  "http_code": 200,
  "response_code": "SUCCESS",
  "response_msg": "Messages queued for delivery.",
  "data": {
    "total_price": 0.0388,
    "total_count": 1,
    "queued_count": 1,
    "blocked_count": 0,
    "messages": [
      {
        "to": "+61411111111",
        "body": "Hello from ClickSend!",
        "from": "SENDERID",
        "message_id": "6811A5CE-E374-5D26-82F5-1D9E52FA9AB3",
        "message_parts": 1,
        "message_price": "0.0388",
        "status": "SUCCESS",
        "date": 1758434400
      }
    ]
  }
}

The fields you'll use most:

Field

Where

Meaning

Message ID

data.data.messages[0].message_id

The unique ID for this message. Quote this when contacting support or looking up delivery receipts.

Status

data.data.messages[0].status

The outcome for this specific message (SUCCESS, INVALID_RECIPIENT, ...). Check this per message — a batch send can return HTTP 200 overall while individual messages fail (see §6).

Cost

data.data.messages[0].message_price

Cost of this one message (string, in your account's currency). data.data.total_price is the sum across every message in the request.

data.response_code / data.response_msg

Top level

The outcome of the request as a whole (SUCCESS + a human-readable message), not of any individual message.

const { data } = await smsApi.sendSms({ sendSmsRequest });

const [message] = data.data?.messages ?? [];
console.log('Message ID:', message?.message_id);
console.log('Status:', message?.status);
console.log('Cost:', message?.message_price);

6. Common errors

The SDK is built on axios: a non-2xx HTTP response rejects the promise as an AxiosError, which you catch with try/catch. But ClickSend also reports some failures — like an invalid recipient in an otherwise-valid batch — inside a 200 OK response body, which won't throw at all. Always check status/response_code, not just whether the call threw.

import axios from 'axios';

try {
  const { data } = await smsApi.sendSms({ sendSmsRequest });

  // Even on HTTP 200, check each message's own status
  for (const message of data.data?.messages ?? []) {
    if (message.status !== 'SUCCESS') {
      console.warn(`Message to ${message.to} failed: ${message.status}`);
    }
  }
} catch (error) {
  if (axios.isAxiosError(error)) {
    console.error(error.response?.status, error.response?.data);
  } else {
    throw error;
  }
}

Error

How it shows up

What it means

Fix

Authentication failure

HTTP 401 Unauthorized — the promise rejects, caught in catch. Body's response_code is MISSING_CREDENTIALS (no username/API key sent) or INVALID_CREDENTIALS (wrong username/API key).

Your Configuration({ username, password }) doesn't match a valid ClickSend account, or was left as undefined because an env var wasn't set.

Double-check CLICKSEND_USERNAME/CLICKSEND_API_KEY are set and copied exactly from the API Credentials page — use the API key, not your dashboard password.

Invalid recipient

Request usually still returns HTTP 200 (response_code: SUCCESS at the top level) — the failure is on the individual message: data.data.messages[0].status is INVALID_RECIPIENT. This does not throw — you must check the status field yourself.

The destination mobile number isn't a valid, deliverable number (bad format, wrong country, disconnected, etc).

Validate/normalize numbers to E.164 (e.g. +61411111111) before sending, and surface per-message status values to your own logs or users.

Insufficient balance

response_code (or a message's status) is INSUFFICIENT_CREDIT, typically alongside an HTTP 400 Bad Request when it blocks the whole request.

Your account has run out of message credit.

Top up credit on the Billing page, or check balance first with ManagementApi.viewAccountDetails().

Next steps

Start sprinting with our API docs

Get all the detail you'll ever need in our full API docs. Learn how to launch your own features or integrate with others.