Node.js

Add the Vonage Verify API to the Backend

Using the Vonage Server SDK

Vonage exposes a standard HTTP API under the hood. That means, in theory, you could integrate Verify by sending raw HTTP requests yourself (for example with fetch, axios, etc.).

So why use the Vonage Node SDK?

Using the SDK helps because:

  • Authentication is easier and safer: Verify uses JWT-based auth with a private key. The SDK handles the signing flow correctly, so you’re less likely to make mistakes.

  • Cleaner code: instead of manually building URLs, headers, and parsing response formats, you call methods like newRequest() and checkCode().

  • Better maintenance: when Vonage updates the API or adds features, the SDK is usually updated to match.

  • Fewer “gotchas”: things like request formatting and expected fields are handled consistently.

Let’s add the SDK to our app.js file:

What’s happening here?

  • The backend needs to prove to Vonage: “I’m allowed to call this API.”
  • Vonage uses JWT (JSON Web Tokens) signed by your private key for that proof.
  • The SDK generates and attaches the JWT automatically whenever it calls Vonage.

Start Verification: POST /verification

This endpoint starts the verification process. The mobile app calls your backend with a phone number. Your backend then asks Vonage to start a verification request.

What happens in this endpoint?

  1. The user enters their phone number in the mobile app.
  2. The mobile app sends the phone number to your backend.
  3. Your backend starts a Verify request:
    • first tries Silent Authentication
    • if that can’t be completed, falls back to SMS

Understanding request_id and check_url:

  • request_id: a unique identifier for this verification attempt. Think of it like a “receipt number” for the verification.

  • check_url: used for Silent Authentication. Your backend returns this URL to the mobile app. The mobile app calls it to prove “this request is coming from the phone number’s mobile network”.

Check Verification Code: POST /check-code

If Silent Auth fails or isn’t available, Vonage will fall back to SMS and the user will receive a code. The mobile app sends the code to your backend along with the request_id.

Callbacks

A callback (also called a webhook) is a URL in your backend that an external service (Vonage) can call to notify you about events.

Instead of your backend constantly asking Vonage: “Has Silent Auth finished yet? What about now? Now?”

Vonage can push the result to you: “Silent Auth finished. Here is the final status.”

That push notification is the callback.

Why are callbacks useful here? Silent Authentication may take time and can complete asynchronously. Using a callback means:

  • Your backend doesn’t have to poll Vonage repeatedly
  • You get a definitive event when the verification changes state
  • It scales better in real systems

To configure the callback URL in the Dashboard, open the Vonage Dashboard:

  1. Go to Applications
  2. Select your application → Edit
  3. Find Network Registry
  4. Enable Verify (SA)
  5. Set the callback URL (where your server listens), for example:

https://your-domain.com/callback

Note: If you’re running locally, Vonage can’t reach http://localhost:3000. You’ll need a public URL (commonly a tunnel like ngrok).

To implement the callback, add a new method to your Express application like so:

For now, we log the event so you can see what Vonage sends. We’ll extend it in the next section to store state and make the mobile app react to those updates.

Add an In-Memory State

A verification flow is not “one request and done”. It has a lifecycle:

  • started
  • pending (silent auth / sms)
  • completed or failed/expired

If you don’t store state anywhere, your backend has no memory of what happened, and:

  • /callback can only log data (not very useful)
  • The app can’t reliably know the current status
  • Debugging becomes painful (“it worked once, then it didn’t…”)

A store gives you a single source of truth.

In production, you would use a database (e.g. Postgres/Redis), but for the tutorial, we can just use a Map.

Step 1: Create the store with a Map

In Node.js, a Map is an easy way to store key/value pairs in memory.

Add this near the top of your app.js:

Add a helper function for validating required request body fields. Add it just below the verificationStore declaration:

This returns the name of the first missing field, or null if all fields are present.

Each entry will be keyed by request_id.

A typical entry might look like:

Step 2: Save initial state when creating a verification

When you call verifyClient.newRequest(...) in /verification, you receive a request_id.

That is the perfect key to store the initial state.

Inside your /verification endpoint, right after you get result:

Now the backend “remembers” that a verification has started.

Step 3: Update state when the callback receives events

A callback (webhook) is Vonage telling your backend: “Something changed. Here’s the new status.”

Instead of only logging the payload, we update the stored state:

Webhook deliveries can be retried, meaning you might receive the same event multiple times. Updating the store like this is naturally idempotent: setting the same status again doesn’t break anything.

Step 4: Add a status endpoint for the mobile app

Now we can provide a simple endpoint the app can call to check the current state:

This is especially useful for Silent Auth because the app can poll every 1–2 seconds for a short period instead of waiting blindly.

Step 5: Add POST /next

The /next endpoint tells Vonage to skip the current workflow channel and move to the next one. In our case, that means skipping Silent Auth and sending an SMS immediately.

This is useful in the Android app when the Silent Auth request fails (bad network, SDK error, etc.) — instead of waiting ~20 seconds for Vonage to time out naturally, the app calls /next and the user gets an SMS right away.

Note: If /next fails, it's not fatal. Vonage will automatically fall back to SMS after the Silent Auth timeout. The Android app should show the SMS input screen regardless of whether this call succeeds.