SDKs & code samples
Status: official SDKs (npm, composer, pip, etc.) are on the roadmap. For now, the API is simple enough that 20-50 lines of helper code in your language is all you need. Code below is production-ready — copy into your project and adapt.
Why not official SDKs yet
The GoSendAPI API is:
- REST + JSON only
- 1 auth header (
X-API-Key) - Standard HTTP semantics (status codes, retries, idempotency)
A generic HTTP client (axios, requests, Guzzle, http.Client) wraps it well. Premature SDKs add maintenance burden without much benefit until the API is large enough. We’ll publish official packages once the API surface stabilizes — probably after Q3 2026.
For now, the code below gives you a clean abstraction that’s 80% of what an SDK would do.
Helper classes
// lib/gosendapi.ts
const BASE_URL = 'https://cloud.gosendapi.com/v1';
export interface MessagePayload {
phone_number_id: string;
to: string;
type: 'text' | 'template' | 'image' | 'video' | 'audio' | 'document' | 'sticker' | 'location' | 'interactive' | 'contacts';
[key: string]: unknown;
}
export class GoSendAPIError extends Error {
constructor(public statusCode: number, public body: unknown) {
super(`GoSendAPI error ${statusCode}`);
}
}
export class GoSendAPI {
constructor(private apiKey: string, private baseUrl: string = BASE_URL) {}
private async request<T>(
method: 'GET' | 'POST' | 'PATCH' | 'DELETE',
path: string,
body?: unknown,
idempotencyKey?: string,
): Promise<T> {
const headers: Record<string, string> = {
'X-API-Key': this.apiKey,
'Content-Type': 'application/json',
};
if (idempotencyKey) headers['Idempotency-Key'] = idempotencyKey;
const res = await fetch(`${this.baseUrl}${path}`, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
});
if (!res.ok) {
const errorBody = await res.json().catch(() => ({}));
throw new GoSendAPIError(res.status, errorBody);
}
return res.json() as Promise<T>;
}
// ─── Messages ──────────────────────────────────────────────
sendMessage(payload: MessagePayload, idempotencyKey?: string) {
return this.request('POST', '/messages', payload, idempotencyKey);
}
sendText(phoneNumberId: string, to: string, body: string, idempotencyKey?: string) {
return this.sendMessage({
phone_number_id: phoneNumberId,
to,
type: 'text',
text: { body },
}, idempotencyKey);
}
sendTemplate(
phoneNumberId: string,
to: string,
templateName: string,
languageCode: string,
components: unknown[],
idempotencyKey?: string,
) {
return this.sendMessage({
phone_number_id: phoneNumberId,
to,
type: 'template',
template: { name: templateName, language: { code: languageCode }, components },
}, idempotencyKey);
}
// ─── Listing ───────────────────────────────────────────────
listMessages(filters: Record<string, string | number> = {}) {
const params = new URLSearchParams(filters as Record<string, string>).toString();
return this.request('GET', `/messages?${params}`);
}
listWabas() {
return this.request('GET', '/wabas');
}
// ─── Templates ─────────────────────────────────────────────
listTemplates(wabaId: string) {
return this.request('GET', `/wabas/${wabaId}/templates`);
}
syncTemplates(wabaId: string) {
return this.request('POST', `/wabas/${wabaId}/templates/sync`);
}
// ─── Webhooks ──────────────────────────────────────────────
listWebhooks() {
return this.request('GET', '/webhooks');
}
createWebhook(config: {
url: string;
events: string[];
type?: 'gosendapi_events' | 'meta_raw';
phone_number_id?: string;
}) {
return this.request('POST', '/webhooks', config);
}
// ─── Self ──────────────────────────────────────────────────
me() {
return this.request('GET', '/me');
}
}
// Usage:
// const client = new GoSendAPI(process.env.GOSENDAPI_KEY!);
// await client.sendText('555123456789', '5491140123456', 'Hello!');Webhook verification (Express):
// lib/verify-webhook.ts
import crypto from 'node:crypto';
import type { Request } from 'express';
export function verifyWebhook(req: Request, secret: string): boolean {
const signature = req.header('X-GoSendAPI-Signature') ?? '';
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(req.body) // Must be raw bytes! Use express.raw()
.digest('hex');
try {
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
} catch {
return false;
}
}Recommended HTTP client setup
Regardless of language, your HTTP client should:
- Set a timeout (30s is reasonable for sends — Meta sometimes takes 20+s)
- Use connection pooling (don’t open a new TCP connection per request)
- Configure retries with exponential backoff (see Error handling)
- Log the
delivery_id/ response correlation for tracing
Testing your integration
We have a few tricks for testing without spending real Meta quota:
Sandbox API key
Use a gsk_test_* key — sends return synthetic responses (no Meta call, no real delivery, no cost). The response includes _sandbox: true and status: "sent_sandbox" so you can distinguish in tests. Your integration code (HTTP, idempotency, retry) works identically to live mode.
Health check
Verify your auth setup:
curl https://cloud.gosendapi.com/v1/me -H "X-API-Key: $GOSENDAPI_KEY"If you get back { "id": "...", "name": "..." } → your key works.
Webhook testing locally
- ngrok:
ngrok http 3000→ use the public URL as your webhook - webhook.site: inspect what we POST without writing code
- Console logging in delivery logs: visible in dashboard → Webhooks
Roadmap
When official SDKs launch they’ll be at:
| Language | Package | Status |
|---|---|---|
| Node.js / TypeScript | npm i @gosendapi/sdk | Planned Q3 2026 |
| PHP | composer require gosendapi/sdk | Planned Q3 2026 |
| Python | pip install gosendapi | Planned Q4 2026 |
| Go | go get github.com/gosendapi/sdk-go | Planned Q4 2026 |
| Ruby | gem install gosendapi | TBD |
Want one prioritized? Vote at hello@gosendapi.com with your language and use case.