WhatsApp interactive
Zero-app path. Approve, deny, or match on the WhatsApp line linked to your Zindua project.

Channel · PushMirror
1-tap approve, emoji, or digit challenges inside your app or browser. No extra consumer app to install. Same API key as email and WhatsApp.
@zindua/sdk v1.4.1
npm install @zindua/sdkPushMirror mark by default, Powered by Zindua signature, check + celebration when approved. This is the same sheet your users see.
New machine sign-in
Tap the same icon on your trusted device.
Your app
PushMirror · now
Chrome · Kinshasa · just now
Zero-app path. Approve, deny, or match on the WhatsApp line linked to your Zindua project.

Native browser notifications on Chrome, Safari, Firefox, and PWAs. Trusted device without a store app.

Use your Firebase or APNs keys so the challenge lands inside the app your users already installed.

Login screen shows one icon. The push offers a few choices. Harder to phish aloud than a spoken code.

Browser login listens for approve or deny. No heavy polling. Session continues when the phone confirms.

No trusted device or timeout? Fall back to WhatsApp or email OTP on the same project and API key.

Who does what
PushMirror orchestrates the challenge. Your WhatsApp line, Web Push, or FCM/APNs delivers it.
Has your app installed, or allowed Web Push on your site. No Zindua consumer app.
Creates the challenge with @zindua/sdk (pushMirror), shows display on login, listens for the result.
Orchestrates challenge state, choices, expiry, webhooks, logs, and OTP fallback. Not a marketing push ESP.
Scenario
How PushMirror interacts with your product when a user signs in from a new browser or phone.
On web or a new device, your app starts login. You call PushMirror from the backend only.
We mint challenge id, type (approve, emoji, or digit), display target, choices, and expiry.
Delivered via WhatsApp interactive, Web Push, or your FCM / APNs app. Payload includes context: device, city, time.
Approve / deny, or tap the matching emoji or digit shown on the login screen.
SSE or webhook tells your backend. Create the session. On deny or timeout, block or fall back to OTP.
Challenge types
Same API. Pick the UX that fits your risk and product tone.
approveC'est moi · Ce n'est pas moi
Best for “someone is signing in from Chrome · Kinshasa”. One tap. Classic PushMirror approve flow.
emoji😄 🚀 🔒 🌴
Login screen shows one emoji. Push shows 3–5 options. User taps the same one. Stops simple push phishing.
digit42 · 17 · 83 · 09
Login shows a two-digit number. User picks the same number on the trusted device.
Setup
Four steps from API key to a live challenge on login.
1
Sign in, create a project, copy your znd_live_ or znd_test_ key. Same key as email and WhatsApp.

2
Link WhatsApp for interactive prompts, enable Web Push, or attach your FCM / APNs credentials (BYO).

3
After a successful login, register the device token (FCM, APNs, or Web Push) against your user id.

4
pushMirror.create from the server. Show challenge.display. pushMirror.listen (SSE) or webhook to open the session.

SDK & stacks
Official guides with the same icons as the Developers menu. WordPress is a plugin download, not a Composer package.
pushMirror.create + SSE listen + webhook HMAC on the server.
npm install @zindua/sdkOpen Next.js guideNode backend with @zindua/sdk. Add Fastify as your HTTP framework.
npm install @zindua/sdkOpen Fastify guideAsync create_challenge and Depends() patterns.
pip install zindua-sdkOpen FastAPI guidecreateChallenge + signed webhook helpers.
composer require zindua/sdkOpen PHP guideAddZindua + CreateChallengeAsync for ASP.NET Core.
dotnet add package Zindua.SdkOpen .NET guideZinduaClient.createChallenge for Spring Boot and Jakarta.
implementation("run.zindua:zindua-sdk:1.0.1")Open Java guideDownload the Zindua Connect plugin for OTP login and WooCommerce. No Composer command.
Download WordPress pluginRegister token via POST /devices. Render PushMirror UI from the FCM payload.
Firebase + Flutter stepsPaste your FCM server key under Push → Config. Full mobile guide.
Open mobile guideUpload your APNs key in Firebase, then use the same FCM path as Android.
Open iOS / APNs guideFlutter SDK is on the roadmap. Until then, call POST /api/v1/challenges from your Dart backend or BFF, and handle the FCM / APNs payload in your Flutter app with the same challenge id + respond endpoint.
import { Zindua } from "@zindua/sdk"; const zindua = new Zindua({ apiKey: process.env.ZINDUA_API_KEY! }); // Backend: start a PushMirror challenge when the user tries to sign inconst challenge = await zindua.pushMirror.create({ to: "+243832499559", // or userId / userExternalId for device lookup type: "emoji", // "emoji" | "approve" | "digit" purpose: "login", channel: "auto", // auto | whatsapp | webpush | fcm | byo context: { device: "Chrome on macOS", city: "Kinshasa" }, fallbackChannel: "whatsapp",}); // Login UI: show challenge.display (e.g. 😄 or 42)// Trusted device: user taps the matching choice in your app / WhatsApp / Web Push await zindua.pushMirror.listen(challenge.challengeId, { onApproved: () => { // create session / redirect }, onDenied: () => { // block or alert },});Beginner → intermediate → advanced tracks: where to put znd_live_, znd_sec_, and the FCM key; Firebase Console steps; project tree; SSE vs webhooks; emoji / digit / approve with a live phone demo.
Product
Context, webhooks, and fallback so PushMirror sits next to your existing OTP.
The login page learns the result as soon as the phone responds. Keep the UX instant without hammering HTTP.
Set app name and logo in the developer dashboard so the challenge feels like your product, not a generic alert.
Get challenge.approved, denied, or expired on your backend with HMAC verification for audit and risk rules.
Pass device, city, IP, and purpose so users recognize a home login vs a suspicious one. Clear PushMirror context every time.
Create a project, link WhatsApp or Web Push, then ship one-tap sign-in with OTP fallback.