Developers

Ship OTPs in minutes

Sneek delivers OTPs and transactional messages over SMS, WhatsApp, and email through pre-approved DLT senders, a verified WhatsApp BSP number, and a warmed email domain. You generate and verify the code; Sneek handles the regulated delivery plumbing.

1. Get an API key

Create an organization and application in the Sneek console, then open Applications → API keys. Keys are shown once. snk_test_… keys hit dev adapters (no real delivery); snk_live_… keys deliver for real. Send every request with Authorization: Bearer <key>.

2. Send a message (curl)

One endpoint, POST /api/messages/send. Set type to "otp" or "transactional" so Sneek selects the correct approved provider template.

bash
curl -X POST https://api.sneek.in/api/messages/send \
  -H "Authorization: Bearer $SNEEK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+919876543210",
    "channel": "auto",
    "type": "otp",
    "body": "Your code to login to ConfHub is 482917. Do not share it."
  }'

Prefer server-rendered DLT templates? Pass template + variables instead of body:

bash
curl -X POST https://api.sneek.in/api/messages/send \
  -H "Authorization: Bearer $SNEEK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+919876543210",
    "channel": "sms",
    "type": "otp",
    "template": "otp_login",
    "variables": { "appName": "ConfHub", "otp": "482917" }
  }'

3. Or use the Node SDK

bash
npm install @sneekin/sdk
ts
import { Sneek } from '@sneekin/sdk';

const sneek = new Sneek({ apiKey: process.env.SNEEK_API_KEY! });

// OTP intent -> uses the approved auth template
await sneek.messages.send({
  to: '+919876543210',
  channel: 'auto',
  type: 'otp',
  body: 'Your code is 482917',
});

// Communication intent -> uses the utility template
await sneek.messages.send({
  to: '+919876543210',
  type: 'transactional',
  body: 'Your booking BK-7781 is confirmed.',
});

The SDK retries transient 5xx/network failures and throws SneekApiError with RFC-7807 problem details on other errors.

4. Drop-in login UI for React

@sneekin/ui renders the whole passwordless flow — enter email/mobile → enter code → signed in.

bash
npm install @sneekin/ui
tsx
import { SneekOtpLogin, createFetchHandlers } from '@sneekin/ui';

export function LoginPage() {
  return (
    <SneekOtpLogin
      title="Sign in to ConfHub"
      {...createFetchHandlers({
        requestUrl: '/api/auth/request-otp',
        verifyUrl: '/api/auth/verify-otp',
      })}
      onSuccess={() => (window.location.href = '/dashboard')}
    />
  );
}
Keep your key server-side. The browser component never holds a Sneek API key. It calls your backend endpoints, which call Sneek with the secret key:
ts
// POST /api/auth/request-otp  (your server, secret key stays here)
import { Sneek } from '@sneekin/sdk';
const sneek = new Sneek({ apiKey: process.env.SNEEK_API_KEY! });

const result = await sneek.sendOTP({
  to: identifier,
  code: generateAndStoreCode(identifier), // you own the code + verification
  appName: 'ConfHub',
  channel: 'auto',
});
return { requestId: result.id, channels: [result.channel], expiresInSeconds: 300 };

Errors

Non-2xx responses return RFC-7807 problem details:

json
{
  "type": "https://sneek.in/errors/unauthorized",
  "title": "Invalid API key",
  "status": 401,
  "detail": "The provided bearer token was rejected."
}

Rate limits & idempotency

  • Sends are rate-limited per application (your plan's per-minute and per-day quota), per recipient, and per source IP. Exceeding a limit returns 429 with a retry_after (seconds) in the problem body.
  • Send an Idempotency-Key header to make retries safe: the first request is processed and its result is replayed for any repeat with the same key, so a dropped connection never sends twice. A retry that arrives mid-flight gets 409.
bash
curl -X POST https://api.sneek.in/api/messages/send \
  -H "Authorization: Bearer $SNEEK_API_KEY" \
  -H "Idempotency-Key: order-4815-otp" \
  -H "Content-Type: application/json" \
  -d '{ "to": "+919876543210", "type": "otp", "body": "Your code is 482917" }'

The Node SDK exposes it directly and pairs it with automatic 5xx retries:

ts
await sneek.messages.send({
  to: '+919876543210',
  type: 'otp',
  body: 'Your code is 482917',
  idempotencyKey: 'order-4815-otp', // same key -> delivered once
});

Channels & intent

  • channel: auto (email → email; mobile → WhatsApp then SMS fallback), or pin to sms / whatsapp / email.
  • type: otp for auth codes, transactional for communications. Omitting it lets Sneek infer intent from the body, which can misclassify digit groups — pass it explicitly.
  • Message wording is governed by Sneek's pre-approved templates; only your App Name and the code vary.

Need help? Email support@sneek.in.