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.
Developers
Use @sneekin/auth to authenticate users or send OTP and generic messages over SMS, WhatsApp, and email. Keep one API key on your server.
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>.
One endpoint, POST /api/messages/send. Set type to "otp" or "transactional" so Sneek selects the correct approved provider template.
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:
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" }
}'npm install @sneekin/authimport { 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.
@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.
npm install @sneekin/uiimport { 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')}
/>
);
}// 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,
};Non-2xx responses return RFC-7807 problem details:
{
"type": "https://sneek.in/errors/unauthorized",
"title": "Invalid API key",
"status": 401,
"detail": "The provided bearer token was rejected."
}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:
await sneek.messages.send({
to: '+919876543210',
type: 'otp',
body: 'Your code is 482917',
idempotencyKey: 'order-4815-otp', // same key -> delivered once
});Need help? Email care@sneek.in.