Developers

One package for login and messages

Use @sneekin/auth to authenticate users or send OTP and generic messages over SMS, WhatsApp, and email. Keep one API key on your server.

1. Get an API key

Create an organization and website in the Sneek console, then open Websites → 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. Install the Node package

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

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

const request = await sneek.auth.requestVerification({ identifier });
const result = await sneek.auth.checkVerification({
    id: request.id,
    code,
});
// result: { status: 'verified', idToken, subject, claims }

// 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. You never name a channel: Sneek picks one per application and the card reports what it chose.

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

export function LoginPage() {
  return (
    <SneekLogin
      title="Sign in to ConfHub"
      {...createFetchHandlers({
        requestUrl: '/api/auth/request',
        verifyUrl: '/api/auth/verify',
      })}
      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  (your server, secret key stays here)
import { Sneek } from '@sneekin/auth';
const sneek = new Sneek({ apiUrl, apiKey: process.env.SNEEK_API_KEY! });

// You ask for a verification. Sneek picks the channel from the
// application's authChannels bitmask and reports it back for display.
const request = await sneek.auth.requestVerification({ identifier });
return {
  requestId: request.id,
  channel: request.channel,
  maskedIdentifier: request.maskedIdentifier,
  expiresAt: request.expiresAt,
};

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 (its 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 care@sneek.in.