DEVELOPER
technicalseries

From Zero to Embedded Checkout: Building an ISV Ecommerce App with Next.js

By Laura Olson | April 24th, 2026

Intro

ISVs integrating payments often face a balancing act between on-brand UX and secure, compliant engineering. North's Embedded Checkout mounts a hosted payment UI in your pages (Form/Fields keep card data in North’s ecosystem) while your server creates sessions and holds API keys.

This guide walks through a Next.js (App Router) + TypeScript demo app: an ecommerce storefront, payment submission and verification, and HTTPS webhooks (including when new merchants are added to your checkout). It compares the three integration methods: Form, Fields, and Direct Post, then guides you through publishing your sandbox checkout to the production environment.

Deploying the checkout form on your app is not the same as live payment processing. Until the checkout is published in North's systems, traffic stays in sandbox even on a production URL. Go live by publishing the checkout, then boarding and attaching production MIDs.

What is North Embedded Checkout?

Embedded Checkout is North’s online checkout product: it embeds a North-hosted payment experience on your pages so shoppers can pay on your domain with less Payment Card Industry (PCI) responsibility than handling raw card data yourself, using a prebuilt form, individual hosted fields, or Direct Post for more control. Your app loads North’s script and creates a checkout session on the server with your API key, then mounts one of those integration styles. The browser receives only a short-lived session token, not your key.

  • UX: Checkout stays on your site instead of a full redirect.
  • PCI: The Form and Fields integration methods keep sensitive payment data out of your app; Direct Post increases your Payment Card Industry (PCI) responsibility and is appropriate for highly custom needs.
  • Truth on the server: Confirm the payment result with the session status endpoint, don’t trust client-only data.

What you’ll build

In this tutorial, we'll build a demo checkout solution for an ISV or merchant that wants to add payments to an ecommerce app:

  1. Vibe code a lightweight storefront (products, cart, checkout page) using Next.js App Router + TypeScript.
  2. Walk through Embedded Checkout end-to-end: session creation on the server, mounting the client integration, and handling completion without trusting the browser alone.
  3. Configure a webhook for notifications when newly boarded merchants are attached to your default checkout.
Embedded Checkout demo store

Integration method overview

For all three Embedded Checkout types, Form, Fields, or Direct Post, session creation is essentially the same; the differences are what you mount and how payment form submission works. Note that because Direct Post increases PCI responsibility, it is recommended only when product requirements and compliance resources call for it.


Form

North renders a complete hosted payment form inside a container div. Your code loads checkout.js, calls checkout.mount(sessionToken, containerId), and verifies the payment response.


ProsCons
Fastest time-to-first-transaction; minimal UI workLess layout control. You’re fitting North’s full form into your page

Fields

North mounts hosted payment fields into your layout; you supply the surrounding markup and the Pay action, then call checkout.submit() when the shopper confirms.


ProsCons
Strong branding control; you decide button labels, spacing, validation UX, etc.Slightly more wiring (mount + explicit submit)

Direct Post

Your page posts raw card data through North’s client SDK (checkout.sendPayment). This is powerful but increases PCI obligations for most real-world storefronts.


ProsCons
Maximum UI control over inputs; useful in tightly controlled or legacy flowsHigher PCI scope; treat as specialized

Get in Touch

Questions about Embedded Checkout, the Checkout Designer, or Next.js? Talk to our team about your integration.

Official reference documentation

The official Embedded Checkout sample code is available in the following GitHub repository: North-EC-Sample-JS (Bun server + static demos for Form, Fields, Direct Post, and a /complete/ flow). It mirrors the same steps as the Integration Guides and can be used alongside this article’s Next.js mapping.

Keep the guides open while you build:

Prerequisites

  • Sign up for a North Developer account.
  • Install Node.js and npm (or pnpm/yarn) for local development.
  • Create a Vercel account (or another host) for an https:// deployment.

1. Create a checkout with the Checkout Designer

Before writing any code, you'll configure a checkout instance in North.


  1. Navigate to the Embedded Checkout product page, select the Embedded Checkout method you'd like to integrate (Form, Fields, or Direct Post) and open the Checkout Designer. This tutorial will cover all three integration methods.
  2. In the Checkout Designer, adjust the settings as relevant to your business case, and note the following:
    • Domains/allowed origins: If you already host an app (or in this case a demo storefront, for example https://steam-and-leaf.vercel.app), configure the allowed domains so the hosted iframe and scripts can initialize in production-like conditions.
    • Receipt behavior: Decide how merchant-facing receipts should behave and where they should be emailed.
    • Webhooks: Any webhook URL must use https://. Until your checkout is published, webhooks will not be functional.
  3. Click Save. You’ll be redirected to the Embedded Checkout dashboard where identifiers and secrets for your checkout instance are provided.
Embedded Checkout demo store

Credentials you’ll need

From the Embedded Checkout dashboard, collect these values for your .env file:

Embedded Checkout demo store

The signup webhook secret is provided in the API Keys modal when you configure a webhook URL in the Checkout Designer. When your integration is published, this webhook will notify you when merchants are attached to this checkout for real payment processing.

2. “Vibe code” an ecommerce app (AI-friendly prompt)

We’ll create a small specialty storefront selling coffee beans, tea, or any catalog that features product cards and a cart. Next.js App Router + TypeScript is a strong fit because:

  • Route Handlers give you first-class /api/* endpoints for session creation and verification on the same deployment.
  • Server/client boundaries are explicit, which helps keep private keys off the client.
  • Type safety reduces mistakes when modeling cart lines and North payloads.

Use the prompt below that corresponds to your Embedded Checkout type (Form, Fields, or Direct Post).

Embedded Checkout demo store

Form integration prompt

Build a Next.js App Router + TypeScript ecommerce demo with Tailwind. Include a home page, product grid, sessionStorage cart, and checkout page. Add POST /api/session (proxy POST https://checkout.north.com/api/sessions with Authorization: Bearer, JSON body checkoutId, profileId, amount, products from the cart). Add POST /api/complete: server-only GET https://checkout.north.com/api/sessions/status with Authorization, SessionToken, CheckoutId, ProfileId—poll until Approved or Declined; return whether payment is approved—clear the cart only then. Load https://checkout.north.com/checkout.js only on the checkout route (Form mode). After fetch('/api/session') returns token, call checkout.mount(token, 'checkout-container') and checkout.onPaymentComplete—then POST /api/complete with token and clientResponse. Add a POST .../signup webhook handler for nightly merchant signup notifications per North docs.

Fields integration prompt

Build a Next.js App Router + TypeScript ecommerce demo with Tailwind. Include a home page, product grid, sessionStorage cart, and checkout page. Add POST /api/session (proxy POST https://checkout.north.com/api/sessions with Authorization: Bearer, JSON body checkoutId, profileId, amount, products from the cart). Add POST /api/complete: server-only GET https://checkout.north.com/api/sessions/status with Authorization, SessionToken, CheckoutId, ProfileId—poll until Approved or Declined; return whether payment is approved; clear the cart only then. Load checkout.js only on checkout. Fields client: fetch('/api/session') → persist tokencheckout.mount(token, 'fields-container') (hosted fields); your markup wraps the container; do not use onPaymentComplete for the Pay flow. On your Pay button call checkout.submit(), then POST /api/complete with the stored token and the submit() response. Add a POST .../signup webhook handler per North docs.

Direct Post integration prompt

Build a Next.js App Router + TypeScript ecommerce demo with Tailwind. Include a home page, product grid, sessionStorage cart, and checkout page. Configure CHECKOUT_TYPE=post (or equivalent). Add POST /api/session that proxies POST https://checkout.north.com/api/sessions with checkoutId, profileId, and amount (Direct Post session body per Post integration guide—typically amount-centric, no cart line items required). Add POST /api/complete: server-only GET https://checkout.north.com/api/sessions/status with Authorization, SessionToken, CheckoutId, and ProfileId—poll until Approved or Declined; return whether payment is approved; clear the cart only then. Load checkout.js only on checkout. Client: fetch('/api/session')checkout.sendPayment(token, { amount, cardNumber, exp, cvv, zip }) with digits-only strings—only if Direct Post fits your PCI posture—then POST /api/complete. Add a POST .../signup webhook handler per North docs.

3. Integrate Embedded Checkout (three parallel paths)

The initial wiring is shared among all three integration methods: create a server session, return a token, mount North’s UI. Then each method diverges.

In the walkthroughs below, paths like /api/session and /api/complete mean “your Next.js Route Handlers” (you can choose other URLs). On the server, those Route Handlers read PRIVATE_API_KEY, CHECKOUT_ID, and PROFILE_ID from the environment and forward requests to North so you'll keep your private key off the client.

Match the Create Session request body (the JSON your /api/session handler forwards to North) to your integration mode: CHECKOUT_TYPE form, fields, or post, as described in the relevant Integration Guide.

Form


For Embedded Checkout Form, send a POST request to North to create a session for the total amount to be sent in the payment request and an array of products in the customer's shopping cart. When both amount and products are sent, amount is optional, but if it's included, North expects it to equal the computed total cost of the products. Your POST /api/session handler should validate that before forwarding. If you don't include products, amount is required.

Your browser calls your API with a cart-shaped body which your Route Handler forwards to North’s session endpoint. JSON is returned that includes a bearer token:

Route Handler example:


Load https://checkout.north.com/checkout.js only on the checkout route (for example using next/script). The checkout.js script exposes a global checkout object after load.

Checkout page example:

Give the mount <div> enough minimum height using CSS on #checkout-container iframe.

Mount the hosted form into an empty container element:


Use onPaymentComplete for immediate browser UX (for example showing a thank-you state or surfacing data from clientPayload). That callback only means that the hosted checkout reported a result to your page. It is not, by itself, proof that North recorded an Approved payment that your server should trust. Post token and clientResponse to /api/complete as in Verify payment approval on the server later in this article, the same server-side step for every integration type.

Fields


For Embedded Checkout Fields, create a session with the cart total and products array: when both amount and products are sent, amount is optional, but if it is included, North expects it to equal the sum of the products. Your POST /api/session handler should validate that before forwarding. If you omit products, amount is required.

Your browser calls your API with a cart-shaped body which your Route Handler forwards to North’s session endpoint. JSON is returned that includes a bearer token:

Route Handler example:


Load https://checkout.north.com/checkout.js only on the checkout route (for example using next/script). The script exposes a global checkout object after load.

Checkout page example: the block below inlines a heading, a “Total” line (same amount you send in POST /api/session), two role="alert" regions (session/mount problems vs. submit/complete), a status line you can use for your own line- or field-level copy, the #fields-container for North to inject iframes, a Pay control outside the mount, and the session, mount, submit(), and /api/complete flow:

Because onLoad can run before the SDK assigns window.checkout, the effect above briefly retries (same idea as waiting for a script queue tick).

Server-side verification is one shared implementation: add POST /api/complete as in Verify payment approval on the server below. The FieldsCheckout example posts token and clientResponse and checks paymentApproved against that route’s contract.

Direct Post


For Embedded Checkout Direct Post, session creation is amount-centric. Your Route Handler forwards to North a body that includes checkoutId, profileId, and amount (additional fields, if any, follow the Direct Post Integration Guide). Example browser payload to your app:

Route Handler example:


Collect card fields only if your business's PCI-secure setup allows Direct Post, then call checkout.sendPayment:

Match field names to your Direct Post config.

After sendPayment, call the same POST /api/complete path as the other methods, see Verify payment approval on the server below, and pass the session token and whatever client response payload you use for server-side logging before you fulfill the order.

4. Verify payment approval on the server

Form, Fields, and Direct Post all use this single next step: a Route Handler such as POST /api/complete that never exposes PRIVATE_API_KEY to the browser and that calls North’s status API, never from the client.

Read the short-lived token (and an optional clientResponse for logging) from the JSON body, then issue:

GET https://checkout.north.com/api/sessions/status


Required HeaderValue
AuthorizationBearer {PRIVATE_API_KEY}
SessionTokenShort-lived session token from create-session (same value passed to checkout.mount / sendPayment).
CheckoutIdYour CHECKOUT_ID env value.
ProfileIdYour PROFILE_ID env value.

Timing: Immediately after onPaymentComplete / submit() / sendPayment(), the API may still return Verified or Open. Poll until status is Approved or Declined, and only trust Approved for order fulfillment.

The status endpoint is not intended for browser calls from your page. Requests with an Origin header will fail.

Return { paymentApproved: true } with a 2xx status only when the polled status is Approved; return { paymentApproved: false, error: "…" } with a 4xx when it is not, so your client can require both a successful HTTP status and paymentApproved: true (as in the FieldsCheckout example). Example src/app/api/complete/route.ts:

5. Merchant signup webhook

North can POST to {webhookURL}/signup when newly boarded merchants associated with your account are added to your default checkout each night.

Configure a base webhook URL in the Checkout Designer so North can POST nightly merchant payloads to {yourWebhookBase}/signup. Because North appends /signup to whatever base you configure, set the base to something like https://your-app.example.com/api/webhooks/north so the full delivery URL is https://your-app.example.com/api/webhooks/north/signup (for example app/api/webhooks/north/signup/route.ts in the App Router).

The designer requires https://. Until the checkout is published, signup webhooks will not deliver.

  • Headers: X-Webhook-Signature, X-Webhook-Timestamp
  • Verification: Use your sec_… signing secret; parse t= and v1= from X-Webhook-Signature and compare HMAC-SHA256(secret, "<timestamp>.<raw_body>") to v1 (hex, timing-safe). Use the exact raw body bytes, do not re-serialize JSON.

See the Integration Guide for the precise header format (t=…,v1=…) and verification steps.

Example Route Handler (must use raw body for signing):

Apple Pay and Google Pay™

Embedded Checkout can surface Apple Pay and Google Pay as alternative payment methods when configured for your checkout and domain. Follow the Integration Guide steps for wallet enablement, domain association files on your host, and sandbox testing.

Submit a test transaction in Sandbox

Use the following test card data to send a payment request in the sandbox environment. North's in-house payment processor will return a real response, not a mocked response that may or may not match the real thing.

Use response trigger values to simulate approvals, declines, and edge cases; don’t only test the happy path.

Deploy to Vercel or another host with https:// so origins, iframes, and webhooks behave realistically. Until your checkout is published, payments processed using your app will hit the sandbox environment even if it's deployed to your production site.

Embedded Checkout demo store

Publish your checkout to production

When you're ready to accept live payments through your checkout, use the Request Publish button from the Embedded Checkout dashboard to request that your checkout be reviewed and certified. After certification, payments submitted with your app will processed in the Production environment. You can edit a published checkout for many non-disruptive settings, but treat major changes with the same care you’d use for any payments configuration: plan, test in sandbox, then promote.

Add MIDs and start processing

Contact us for more information about boarding production merchants (MIDs) for North payment processing, and attaching them to your checkout instance so live transactions route through your checkout configuration. Until real merchants are boarded and linked, your integration is effectively a sandbox demo: no seller is actually getting paid through your software. Boarding and attaching MIDs is what turns that demo into a live product. Each seller you add can run real transactions through the checkout you built.

Embedded Checkout demo store

Closing

Embedded Checkout lets businesses ship on-brand payments without reinventing PCI-sensitive infrastructure. Form and Fields are the usual choices for ecommerce, Direct Post is specialized, and server verification plus HTTPS webhooks turns a basic ecommerce store into a trustworthy business system. Start in the Checkout Designer, mirror those settings in environment variables, keep secrets on the server, verify Approved payments via session status, then promote from sandbox to production with confidence.


Start your free Developer account and try it now.


©2026 North is a registered DBA of NorthAB, LLC. All rights reserved. North is a registered ISO of BMO Harris Bank N.A., Chicago, IL, Citizens Bank N.A., Providence, RI, The Bancorp Bank, Philadelphia, PA, FFB Bank, Fresno, CA, Wells Fargo Bank, N.A., Concord, CA, and PNC Bank, N.A.