Skip to main content
Put Natural’s payment form on your own checkout page. Your server creates a payment intent. The form takes the card and runs the payment. Start in Sandbox. There the form loads on any site, so you can build on localhost. Set NATURAL_API_KEY to your Sandbox API key and call https://api.sandbox.natural.com. Before you take real payments, add your site.

Create the intent

Create the intent on your server with POST /payment-intents.
Use the order as the idempotency key, so a retry within 48 hours returns the same intent instead of creating a second one. The response includes data.attributes.clientSecret. Store data.id with the order, and send the secret to the browser. Treat it like a password. Don’t log it or put it in a URL.

Add the form to your page

Create the clientSecret Promise once, outside render. A new clientSecret or theme mounts a new form. PaymentForm removes the form when it unmounts. It works with server rendering, Strict Mode, and the Next.js app router.

Confirm the payment

When the payer is done, onComplete gets { paymentIntentId, status }. It fires once. If the intent had already finished when the form mounted, it fires right away, so a payer who presses Back to your checkout page sees your confirmation again. Show your confirmation on onComplete. Don’t ship the order from there. Ship it when the paymentIntent.completed webhook arrives on your server. The webhook arrives even if the payer closes the page. A processing payment can still fail. If it does, you get a cardPayment.failed webhook and the intent goes back to open. The form keeps showing “Payment processing”. To let the payer try again, render PaymentForm with a new key.

Handle errors

When onError fires, the form is done. It can’t take a payment anymore. To try again, render PaymentForm with a new key. An error is a plain { code, message } object. Match on code. We never rename or remove a code, but we do add new ones, so handle a code you don’t know. The message is for your logs. Its wording can change. A problem the payer can fix, like a declined card, shows inside the form. It doesn’t call onError.

Show the order on your page

The form shows the total, your business name, and your policies. Make sure your page shows:
  • Each item, any tax or fee, and the total with its currency, matching the intent’s amount
  • Your country, and an email address or phone number for support
  • Your delivery policy, if you ship goods
To change the order, update the intent on your server. The next time the payer presses Pay, the form shows the new total and asks them to press Pay again.

Match your page

The form has no background of its own. Its Pay button uses the brand color from your Natural account. On a dark page, pass theme="dark":
Popups use the same theme.

Place the form

  • The form grows to fit what it shows. Don’t give PaymentForm or its parents a fixed height with overflow: hidden.
  • Size and position the form with className on PaymentForm. natural.js sets the size of its own frames.
  • Popups, such as a 3-D Secure challenge or a sign-in code, open over your whole page.
  • Serve your page over HTTPS. The form doesn’t load on plain http, except on localhost in Sandbox.

Test in Sandbox

Your page code doesn’t change between Sandbox and live. The secret tells the form which one it’s in. Pay with the test cards. When the form asks for a code, to save a card or to sign in, enter 000000. Sandbox skips the 3-D Secure challenge popup, Apple Pay, Google Pay, and the receipt email.

Go live

Create the intent with your production API key at https://api.natural.com. Then list every site that shows the form. Open Developers, then API keys, and add them under Checkout domains. A site is a scheme, host, and port, like https://shop.example.com. Browsers treat example.com and www.example.com as two sites, so list both if you use both. If you’re a platform, your sites cover the intents you create for your merchants. On a site you haven’t listed, onError gets domain_not_allowed.

Content Security Policy

If your page sets a Content Security Policy, allow Natural’s checkout origin in script-src and frame-src:
That’s the whole list. natural.js makes no network requests from your page and adds no styles. PaymentForm adds the natural.js script tag without a nonce. If your policy uses nonces, keep the source above or add 'strict-dynamic'. If your page enforces Trusted Types, allow the one policy PaymentForm creates:

Browser support

The form opens no popup windows, so it works in webviews and in-app browsers. Apple Pay and Google Pay may not appear there.