lang_undefined
lang_undefined
lang_undefined
- Pair an Android phone in your dashboard (Devices, Add device, scan the QR code) and copy its device ID.
- Create an API key under Tools, API Keys, with the sms_send permission (and wa_send for WhatsApp). Copy the secret into an environment variable; never into source.
- Node.js 18 or newer (for built-in fetch). Older Node: npm install undici and import fetch from it.
lang_undefined
One call helper, three exported functions. URLSearchParams builds the form body the API expects.
// Node 18+ (built-in fetch). No SDK needed.
const SHARKSMS = "https://sharksms.com/api";
const { SHARKSMS_SECRET, SHARKSMS_DEVICE } = process.env;
async function call(path, params) {
const res = await fetch(`${SHARKSMS}${path}`, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ secret: SHARKSMS_SECRET, ...params }), // form body, not JSON
});
const body = await res.json(); // HTTP is always 200; read body.status
if (body.status !== 200) throw new Error(`SharkSMS ${body.status}: ${body.message}`);
return body.data;
}
export const sendSms = (phone, message, sim = 1) =>
call("/send/sms", { mode: "devices", device: SHARKSMS_DEVICE, sim, phone, message });
export const sendWhatsApp = (recipient, message) =>
call("/send/whatsapp", { account: process.env.SHARKSMS_WA_ACCOUNT, recipient, type: "text", message });
export async function smsStatus(id) {
const q = new URLSearchParams({ secret: SHARKSMS_SECRET, id, type: "sent" });
const body = await (await fetch(`${SHARKSMS}/get/sms.message?${q}`)).json();
return body.data.status; // queued | pending | sent | failed
}
// usage
const { messageId } = await sendSms("+15551234567", "Order #4821 shipped. Arriving Thursday.");
console.log(messageId, await smsStatus(messageId));
To receive replies, add a webhook in your dashboard pointing at an Express route like this one. Acknowledge with 200 inside five seconds and do the work after.
// Express: receive replies (see /docs/webhooks)
import express from "express";
const app = express();
app.use(express.urlencoded({ extended: true }));
app.post("/sharksms/webhook", (req, res) => {
if (req.body.secret !== process.env.SHARKSMS_WEBHOOK_SECRET) return res.sendStatus(403);
res.sendStatus(200);
const { type, data } = req.body; // data.phone, data.message
// ...
});
lang_undefined
Send to your own phone first. Then call GET /api/get/sms.message with the returned messageId and type=sent and watch it go queued, sent. If it stays queued, the paired phone is off, offline or battery-optimised; see the Android gateway page.
lang_undefined
- The API reads a form body, not JSON. A JSON body is ignored and you get status 400 for missing parameters.
- HTTP is always 200. Branch on the JSON status field, never on the HTTP status.
- No deduplication. A retry after a timeout can send twice; record the messageId on success and check status before resending.
- Do not JSON.stringify the body. The API reads form fields; URLSearchParams sets the right content type for you.