Sigil API

Two API calls to verify any phone number. Prepaid credits, no contracts.

Authentication

All API requests require an X-API-Key header. Generate keys from your dashboard.

# All requests need this header
X-API-Key: sg_live_••••••••••••••••

Keys begin with sg_live_ and are shown once at creation. Store them securely. They cannot be retrieved again.

Credits

Each successfully sent verification costs 1 credit (€0.09). Credits are deducted when the SMS is dispatched, not when the code is verified. If SMS delivery fails, the credit is automatically refunded.

Top up credits from your dashboard. You'll receive a low-credit alert email when your balance falls below 10.

Send OTP

POST /v1/verify/send

Sends a 6-digit one-time code to the given phone number via SMS. The message also includes a rejection link so the recipient can flag a number they don't own.

Body paramDescription
phonerequiredPhone number in E.164 format (e.g. +4512345678)
Request
POST https://api.sigilid.io/v1/verify/send
X-API-Key: sg_live_••••••
Content-Type: application/json

{
  "phone": "+4512345678"
}
Response 200 OK
{
  "ok": true,
  "expires_in": 300
}
Response 402 no credits
{ "error": "Insufficient credits" }
Response 429 rate limited
{ "error": "Too many verification attempts for this number" }

Rate limit: 3 send attempts per phone number per 10 minutes. Sending the same number again within the window is idempotent: a new code is not generated if one is already active.

Check OTP

POST /v1/verify/check

Validates the code the user entered. The code expires after 5 minutes and is deleted on first successful match. Replay is not possible.

Body paramDescription
phonerequiredSame number passed to /send
coderequired6-digit code the user entered
Request
POST https://api.sigilid.io/v1/verify/check
X-API-Key: sg_live_••••••
Content-Type: application/json

{
  "phone": "+4512345678",
  "code": "847291"
}
Response 200 verified
{ "verified": true }
Response 400 wrong code
{ "verified": false, "error": "invalid" }
Response 400 expired or max attempts reached
{ "verified": false, "error": "expired" }

After 5 wrong attempts the code is invalidated. Call /send again to issue a new one.

Webhooks

Set a webhook URL in your dashboard to receive a POST request when a user clicks the rejection link in an SMS.

Each delivery is signed with an X-Sigil-Signature header: an HMAC-SHA256 of the raw request body using your webhook secret. Verify this before trusting the payload.

# Verify the signature (Node.js example)
const sig = crypto
  .createHmac('sha256', process.env.SIGIL_WEBHOOK_SECRET)
  .update(rawBody)
  .digest('hex')

if (sig !== req.headers['x-sigil-signature']) {
  return res.status(401).send('Invalid signature')
}
Webhook payload
{
  "event": "verification.rejected",
  "phone_hash": "sha256-of-phone-number",
  "tenant_id": "your-tenant-id",
  "timestamp": "2026-06-23T10:00:00Z"
}

Rejection link

Every SMS includes a unique single-use link (e.g. https://api.sigilid.io/reject/abc123…). When the recipient clicks it:

This lets legitimate owners of a number flag when someone else is trying to verify it using their phone.

Error codes

HTTP statusMeaning
400Bad request, missing or invalid parameters
401Missing or invalid API key
402Insufficient credits, top up your account
422Invalid phone number, must be E.164 format
429Rate limit exceeded
502SMS delivery failed, credit was refunded