✅ Meta App Review approved — GoSendAPI Cloud is live. Sign up free →
SDKs

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;
  }
}

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:

LanguagePackageStatus
Node.js / TypeScriptnpm i @gosendapi/sdkPlanned Q3 2026
PHPcomposer require gosendapi/sdkPlanned Q3 2026
Pythonpip install gosendapiPlanned Q4 2026
Gogo get github.com/gosendapi/sdk-goPlanned Q4 2026
Rubygem install gosendapiTBD

Want one prioritized? Vote at hello@gosendapi.com with your language and use case.

What’s next