# SignOps > Push notifications and login verification, on one API. One API key, one user id, one bill. SignOps is a developer API with five products that share the customer's own user ids: - Push: send push notifications to Android (FCM), iOS (FCM or APNs) and the web from a server. Users, topics, scheduling, templates, frequency caps, a composer for non-developers, delivery logs and signed webhooks. Customers upload their own Firebase and Apple keys. - Approve: approve a login or payment with a push to a phone the user already trusts. Number matching and a biometric on every request; the phone signs a fresh challenge with a key from the Android Keystore or iOS Secure Enclave. SDKs for Android, iOS, React Native and Flutter. - Passkeys: WebAuthn passkeys on the customer's own domain, on web, Android and iOS. SignOps runs the server side. - Authenticator: codes from Google Authenticator or any TOTP app (RFC 6238). QR enrolment, 10 backup codes, each code once, and a lock after 5 wrong codes in 15 minutes. The key is encrypted; backup codes are kept as HMACs. 10,000 checks a month on Free, 100,000 on Starter and 500,000 on Pro, then $1.40 per 50,000. Every answered check counts, right or wrong. - Email OTP: send and verify 6-digit codes. Stored as a keyed hash, 10 minute expiry, 5 tries. Live codes go from the customer's own domain on every plan (DKIM through Amazon SES, US East); test keys send to test addresses. English and Hindi. Sign-in and verification codes only, no marketing email. Per-address, per-IP and daily limits, a do-not-send list, and warnings, 24-hour pauses and stops on bounces, spam complaints or unused codes. - Magic links: sign-in links by email (POST /v1/magic-links, then POST /v1/magic-links/verify with the token). The link opens the customer's own page on their verified domain or a listed host with a single-use token, valid 15 minutes. Same limits, do-not-send list and price as an email code. Push also carries buttons (up to 3, each with an id and a link; the tapped id is reported as the open's action), sound, badge, Android channel, iOS category and thread, priority and time to live. A ready-made service worker for web push is at https://api.signops.dev/push-sw.js. On Starter and Pro only, because each writes to the database per use, each with a daily cap per organisation: - POST /v1/verify: passkey, then Approve, then authenticator, then email code, in that fixed order, keeping only the steps the user can do. Each step is billed as its product. - Risk signals: facts about a sign-in, each with its source, never a score: first sign-in, new device, new country, impossible travel, Tor exit, datacenter network. On passkey sign-ins and verify when turned on, or POST /v1/signals for the customer's own sign-ins. - New-login alerts: a push, or an email from the customer's domain, when a sign-in comes from a new device or country. - Notification inbox: inbox: true on a push, or POST /v1/inbox; the app lists it with the publishable key and an inbox token from the server. $0.000042 a stored message, kept 30 days on Starter and 90 on Pro. - Live Activities (iOS, straight to Apple) and ongoing notifications (Android), started, updated and ended by the customer's own ref. $0.000028 an update. Login system plugins: @signops/better-auth (passkey and Approve sign-in as Better Auth sessions) and @signops/supabase (a SignOps sign-in turned into a Supabase session on the server). Status: https://status.signops.dev SignOps is made by the people behind Triplli (https://triplli.com/), quoting software for travel agencies, and Cabaro (https://cabarobytriplli.triplli.com/), booking software for cab operators. Coding agents can use SignOps through its MCP server at https://api.signops.dev/mcp (streamable HTTP, secret key in the Authorization header): send pushes, manage devices, topics and templates, create approvals, and check or remove a user's authenticator. See https://signops.dev/docs/#mcp, and client configs at https://github.com/signops-dev/signops-mcp. DPDP Act tools on every plan: DELETE /v1/users/:user_id erases everything held under a user id in one call (devices, passkeys, authenticator, approvals, consent, pushes and the log lines that name them), GET /v1/users/:user_id/export returns it as JSON, and POST /v1/users/:user_id/consent records consent; marketing pushes can be set to skip users without a yes. SignOps is not a login system. It works next to Supabase Auth, Better Auth, Firebase Auth, Auth0, Amazon Cognito or a custom one. ## Pricing (US dollars; customers in India pay in rupees, with GST) Start using it for free. Payments in US dollars are coming soon. If you reach a limit, email hello@signops.dev. Three plans. Use past a paid plan's included amounts is paid from a prepaid wallet the customer tops up (from $7); it stops when the wallet is empty, and nothing is billed after the month. If a plan's autopay debit fails, the organisation moves to Free at once with email codes off until a plan is paid again. Payment questions and disputes: payments@signops.dev. - Free, $0, a card only past the free amounts: one person, 1,000 push devices, 100 approvals and 1,000 passkey sign-ins a month, 10,000 authenticator checks a month, 500 email codes once to try, approval records 7 days, no delivery logs. A refill, $0.70, gives the month's Free limits again except email codes, up to twice a month. - Starter, $6.99 a month: 5,000 push devices (then $0.0028 a device, $0.0014 above 1 million), 100 approvals a day, 2,000 email codes and 100,000 authenticator checks and 50,000 passkey sign-ins a month included, delivery logs 7 days, approval records 90 days, 3 apps, 50 team members. - Pro, $20.99 a month: 10,000 push devices (then $0.0021 a device, $0.0014 above 1 million), 300 approvals a day, 10,000 email codes, 500,000 authenticator checks and 200,000 passkey sign-ins a month, delivery logs 30 days (longer by agreement), approval records 1 year, 10 apps, unlimited team. On Starter and Pro, approvals past the day's allowance are $0.00028 each, and email codes past the plan's 2,000 or 10,000 a month are $0.001 each ($0.0008 above 100,000 and $0.0006 above 1 million a month). Authenticator checks and passkey sign-ins past the plan are $1.40 per 50,000 ($0.000028 each); on Free, checks pause after 10% grace and passkey sign-ins at 1,000, until the 1st. Expired approval requests are free. Inbox messages are $0.000042 each stored and Live Activity updates $0.000028 each, none included. An invoice in the customer's name comes with Starter and Pro. ## Pages - [Push](https://signops.dev/push/) - [Approve](https://signops.dev/approve/) - [Passkeys](https://signops.dev/passkeys/) - [Authenticator](https://signops.dev/authenticator/) - [Email OTP](https://signops.dev/email-otp/) - [Pricing](https://signops.dev/pricing/) - [Docs](https://signops.dev/docs/), also as Markdown: https://signops.dev/docs.md - [OpenAPI 3.1](https://signops.dev/openapi.json): every endpoint, request field and response. - [llms-full.txt](https://signops.dev/llms-full.txt): this file, the docs and every guide, comparison and post in one Markdown file. - [Examples on GitHub](https://github.com/signops-dev/signops-examples): FCM HTTP v1 push from Node.js (directly and through SignOps), passkeys in a Next.js App Router app, Expo push with native FCM and APNs tokens. - [Postman workspace](https://www.postman.com/signops/signops-api): every API request as a public Postman collection, with an environment for a test key. - [Compare](https://signops.dev/compare/) - [Security](https://signops.dev/security/) - [FAQ](https://signops.dev/faq/) ## Free tools - [Web push tester](https://signops.dev/tools/web-push-test/): send a real web push to this browser; shows the request, the push service's status code and the payload as received. No account. - [Passkey support checker](https://signops.dev/tools/passkey-check/): what the browser and device support for passkeys (platform authenticator, conditional UI, hybrid, sync, PRF). Runs in the browser, nothing sent. - [VAPID key generator and checker](https://signops.dev/tools/vapid-keys/): make a web push VAPID key pair, check a public and private key belong together, and check a vapid Authorization header (signature, aud, exp, sub, subscription key) for the causes of a 403. Runs in the browser, nothing sent. - [TOTP generator and code checker](https://signops.dev/tools/totp/): a TOTP secret, its otpauth URI and QR code, live codes, and which time step a pasted code matches. Runs in the browser, nothing sent. - [OTP cost calculator](https://signops.dev/tools/otp-cost-calculator/): monthly cost of OTP codes in India by SMS (MSG91, Twilio), WhatsApp (Meta's authentication rate) and email (Amazon SES, MSG91), from each provider's price page. ## Guides and comparisons - [Which product to use, and when](https://signops.dev/guides/which-product/): Push, Approve, passkeys, authenticator codes and email OTP matched to the jobs they do: sign-up, sign-in, two-step, payments, recovery and notifications. - [Set up push on Android](https://signops.dev/guides/android-push/): From a new Firebase project to a push on your Android phone: google-services.json, the service account key, the device token, and a first send. - [Set up push on iOS](https://signops.dev/guides/ios-push/): How to make an APNs .p8 key, find the Key ID, Team ID and bundle id, turn on push in Xcode, get the device token and send a first push. - [Set up web push](https://signops.dev/guides/web-push/): Web push with keys SignOps makes for you: a service worker, the permission prompt, the subscription on your server, and iPhone home screen apps. - [Set up push in React Native, Expo and Flutter](https://signops.dev/guides/react-native-flutter-push/): Use the Firebase messaging package your framework already has, register the token with SignOps, and send to Android and iOS from one call. - [Set up Approve](https://signops.dev/guides/approve/): Let users approve a sign-in or a payment on a phone they already use: enrol the phone after login, ask it from your server, and show the number to match. - [Set up passkeys on your website](https://signops.dev/guides/passkeys-web/): Your domain, the sign-in page origins, a registration token from your server, the browser prompt and the check before a session starts. - [Set up passkeys in your Android and iOS apps](https://signops.dev/guides/passkeys-apps/): Find the SHA-256 of your signing certificate, the Team ID and bundle id, host assetlinks.json and apple-app-site-association, and add Associated Domains. - [Set up authenticator app codes](https://signops.dev/guides/authenticator/): A two-step settings page with a QR code, backup codes shown once, the code check at sign-in, a lost phone, the lock, and how to test it on your phone. - [Set up email OTP and magic links](https://signops.dev/guides/email-otp/): Test with your own address first, then add your domain and its DNS records, send and check codes, and switch to sign-in links if you prefer. - [A OneSignal alternative, now that free mobile push stops at 1,000 users](https://signops.dev/onesignal-alternative/): OneSignal's free plan now stops mobile push at 1,000 monthly users. What it costs to stay, the free alternatives, and how SignOps compares. - [OTP service providers in India, compared on price and setup](https://signops.dev/otp-service-provider-india/): SMS, WhatsApp, email and push OTP providers in India with prices per code, DLT rules, and the options that need no DLT registration. - [An MSG91 alternative for apps that want more than SMS](https://signops.dev/msg91-alternative/): What MSG91 charges for SMS and email OTP, where it is the right choice, and when SignOps push, approvals and passkeys cost less. - [Twilio Verify pricing, and a cheaper alternative](https://signops.dev/twilio-verify-alternative/): Twilio Verify is $0.05 a verification on every channel. What 100,000 sign-ins cost, and email OTP at $1 per 1,000 codes instead of $50. - [Free push notification services for Android, iOS and the web](https://signops.dev/free-push-notification-service/): Every free push notification option in 2026, what the free tier covers, and what you still have to build: FCM, Expo, OneSignal, Pusher, Truepush and SignOps. - [Migrating from the FCM legacy API to HTTP v1](https://signops.dev/blog/fcm-http-v1-migration/): The FCM legacy API is shut down. How to move to HTTP v1: service account tokens, the new payload, sending to many tokens, and Node, PHP and cURL examples. - [FCM says success but the notification never arrives](https://signops.dev/blog/fcm-notification-not-received/): Why Android does not show FCM notifications when the app is closed or killed: message types, priority, Doze, permissions, stale tokens and OEM battery savers. - [FCM error codes, and what to do about each](https://signops.dev/blog/fcm-error-codes/): Every FCM HTTP v1 error code: UNREGISTERED, INVALID_ARGUMENT, SENDER_ID_MISMATCH, QUOTA_EXCEEDED and more, with the Admin SDK codes and when to retry. - [APNs error codes, and what to do about each](https://signops.dev/blog/apns-error-codes/): Every APNs error reason Apple documents, from BadDeviceToken and DeviceTokenNotForTopic to 410 Unregistered and the provider token errors, with fixes. - [Why push notifications go missing on Xiaomi, Oppo, Vivo and Realme](https://signops.dev/blog/push-notifications-xiaomi-oppo-vivo/): Battery savers on Xiaomi, Redmi, Poco, Oppo, Realme, Vivo and OnePlus stop apps and drop pushes. What developers can change in the app and what users must switch on. - [Is Firebase push notification free or paid?](https://signops.dev/blog/firebase-push-notification-pricing/): Yes. FCM is free on every Firebase plan, with no message limit. The quotas: 600,000 messages a minute, 240 a minute to one phone. What costs money around it. - [Sending push notifications from a Node.js server](https://signops.dev/blog/send-push-notification-node-js/): Send FCM push notifications from Node.js: firebase-admin setup, one user, many tokens, topics, all users, scheduling and cleaning up dead tokens. - [Expo push notifications work in development but not in the APK](https://signops.dev/blog/expo-push-notifications-not-working/): The common reasons Expo push notifications stop in production builds: FCM v1 credentials, google-services.json, Expo Go limits, receipts and Android channels. - [What an SMS OTP costs in India, and what DLT asks of you](https://signops.dev/blog/sms-otp-cost-india/): SMS OTP charges in India per message, what 1,000 and 1 lakh OTPs cost, what DLT registration involves, and the options that need no DLT. - [Supabase "email rate limit exceeded": the fix](https://signops.dev/blog/supabase-email-rate-limit/): Supabase's built-in email sender is for testing and allows only a few emails an hour. How custom SMTP raises the limit, and other ways to send sign-in codes. - [Email OTP in Better Auth, end to end](https://signops.dev/blog/better-auth-email-otp/): Set up the Better Auth email OTP plugin, choose a sender for the codes, and handle expiry, tries and rate limits in production. - [Firebase Auth has no email OTP. Here is how to add one](https://signops.dev/blog/firebase-auth-email-otp/): Firebase Auth offers email links, not 6-digit email codes. How to build email OTP sign-in with a Cloud Function and a custom token. - [Email OTP or SMS OTP?](https://signops.dev/blog/email-otp-vs-sms-otp/): Email OTP and SMS OTP compared on price in India, DLT, delivery, SIM swap and phishing risk, with when to use each. - [Passkeys or OTP?](https://signops.dev/blog/passkeys-vs-otp/): How passkeys work, why they cannot be phished like an OTP, which devices support them, and how to add them next to the login you already have. - [Push authentication, MFA fatigue and number matching](https://signops.dev/blog/push-authentication-number-matching/): What push authentication is, how MFA fatigue attacks beat it, why number matching stops them, and how it compares with an OTP. - [The RBI's 2025 authentication directions, for developers](https://signops.dev/blog/rbi-authentication-directions-2025/): What the RBI's Authentication Mechanisms for Digital Payment Transactions Directions, 2025 ask of apps from 1 April 2026, and the alternatives to SMS OTP they name. - [WebAuthn and passkey errors, and what each one means](https://signops.dev/blog/webauthn-errors/): Every error navigator.credentials.create() and get() throw: NotAllowedError, InvalidStateError, SecurityError for rp.id, ConstraintError, with causes and fixes. - [Passkey autofill: show passkeys in the username field](https://signops.dev/blog/passkey-autofill/): Set up passkey autofill with mediation conditional: the autocomplete attribute, the feature check, an empty allowCredentials, aborting for the button, and fixes. - [Web push errors, and what to do about each](https://signops.dev/blog/web-push-errors/): Every status a web push service returns, from 201 to 410 Gone, 403 for VAPID key problems, 413 payload too large and 429, with what to delete, fix or retry. - [Keeping FCM tokens current](https://signops.dev/blog/fcm-token-refresh/): When an FCM token changes, how to send it to your server on every start, when to delete it (UNREGISTERED, 270 days, one month stale), and the move to Firebase Installation IDs. - [Email OTP in Next.js with the App Router](https://signops.dev/blog/nextjs-email-otp/): Add 6-digit email code sign-in to Next.js: two Route Handlers, the otp_id in an httpOnly cookie, a client form with one-time-code autofill, and every error to handle. - [Email OTP login in Laravel](https://signops.dev/blog/laravel-email-otp/): Add 6-digit email code sign-in to Laravel with the HTTP client, the session, throttle middleware and Auth::login, and handle expiry, tries and rate limits. - [Email verification in React Native](https://signops.dev/blog/react-native-email-verification/): Verify an email in a React Native or Expo app with a 6-digit code: a backend that keeps the API key, TextInput props for one-time-code autofill, and secure session storage. - [iOS silent push not received](https://signops.dev/blog/ios-silent-push-not-working/): Why an iOS background push never wakes the app: content-available, apns-push-type background, priority 5, the background mode, force quit and throttling. - [Web push received but not shown](https://signops.dev/blog/web-push-not-showing/): Why a web push arrives but no notification shows, or Chrome shows its generic notice: waitUntil, userVisibleOnly, tag and renotify, and OS settings. - [Web push on iPhone and iPad](https://signops.dev/blog/web-push-ios/): What iOS needs for web push: version 16.4, a Home Screen web app, a standalone manifest and a prompt from a tap. With detection code and a service worker. - [The Android 13 notification permission, POST_NOTIFICATIONS](https://signops.dev/blog/android-notification-permission/): Notifications are off by default on Android 13 and later. How to declare and ask for POST_NOTIFICATIONS in context, handle two denials, and test it with adb. - [Send a test push to an iPhone with curl](https://signops.dev/blog/apns-curl/): Make an APNs JWT from your .p8 key with openssl and send an alert or a background push with curl over HTTP/2, with every header and the errors you may see. - [Expo push notification errors, and what to do about each](https://signops.dev/blog/expo-push-errors/): Every Expo push ticket, receipt and request error: DeviceNotRegistered, MessageTooBig, MismatchSenderId, InvalidCredentials, TOO_MANY_REQUESTS, with fixes. - [Why your server rejects correct authenticator codes](https://signops.dev/blog/totp-code-invalid/): Authenticator app codes rejected by your server: clock drift, base32 secrets, leading zeros, ignored parameters and reused codes, with a TOTP check in Node. - [Cloudflare D1 free tier limits, and what counts as a row written](https://signops.dev/blog/cloudflare-d1-free-tier-limits/): D1 on Workers Free allows 100,000 rows written and 5 million read a day per account. What counts as a write, what happens past it, and how to stay under.