Quickstart

CoverPay is one checkout for Klarna, Affirm, Afterpay and Zip, smart-routed for each order, with CoverPay's own pay-in-4 filling in when no provider approves. It works like Plaid Link: your server creates a link token, your page or app opens Link with it, and your server exchanges the public token Link hands back.

Why a link token
The amount, order and customer live on the link token, created with your secret key. Nothing about the payment comes from the browser or the app, so it can't be changed there.

How it fits together

  1. 1
    Your server creates a link token
    POST /v1/link/token/create with your secret key and the order amount from your own catalog.
  2. 2
    Your page or app opens Link
    Web: CoverPayLink.create({ token }).open(). React: useCoverPayLink. iOS: CoverPayLink.open(linkToken:).
  3. 3
    The shopper picks a plan
    CoverPay shows the offers it routed, the shopper approves with the provider, and Link calls onSuccess with a public token.
  4. 4
    Your server exchanges the public token
    POST /v1/link/public_token/exchange returns the payment. Your webhook is the source of truth for whether it's paid.

1. Get your keys

In the dashboard, create a test key (cp_test_…). Keep it on your server. Test keys work only in sandbox; live keys (cp_live_…) only in production.

2. Create a link token (server)

Node
const res = await fetch('https://api.coverpayme.com/v1/link/token/create', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'x-api-key': process.env.COVERPAY_SECRET_KEY },
  body: JSON.stringify({
    amount: 12000,              // cents, from YOUR catalog or cart, never from the client
    currency: 'USD',
    merchantName: 'My Store',
    orderId: 'order_123',       // your id; it comes back on the exchange and in webhooks
    customerId: 'user_456',
    customerEmail: 'buyer@example.com',
  }),
});
const { link_token, expiration } = await res.json(); // link_token: "lt_test_…"

3. Open Link (client)

Web
import { CoverPayLink } from '@coverpay/sdk';

const callbacks = {
  onSuccess: (publicToken, metadata) => {
    // POST publicToken to your server (step 4). metadata.provider: "klarna" | "affirm" | "afterpay" | "zip" | "coverpay"
  },
  onExit: (error, metadata) => {
    // closed, cancelled (error null) or failed (error.code, error.message)
  },
};

// Providers take over the whole page and then CoverPay sends the shopper back here: call once on load.
CoverPayLink.handleRedirect(callbacks);

const link = CoverPayLink.create({ token: linkToken, ...callbacks });
document.querySelector('#pay-later').addEventListener('click', () => link.open());
React
import { useCoverPayLink } from '@coverpay/react';

const { open, ready } = useCoverPayLink({ token: linkToken, onSuccess, onExit }); // handles the redirect back too
return <button disabled={!ready} onClick={() => open()}>Pay later</button>;
iOS (Swift)
CoverPayLink.open(linkToken: linkToken, from: self) { result in
  switch result {
  case .success(let payment):  sendToServer(payment.publicToken)   // exchange on your server
  case .failure(.userCancelled): break
  case .failure(let error):    show(error)
  }
}

4. Exchange the public token (server)

Node
const res = await fetch('https://api.coverpayme.com/v1/link/public_token/exchange', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'x-api-key': process.env.COVERPAY_SECRET_KEY },
  body: JSON.stringify({ public_token: publicToken }),
});
const payment = await res.json();
// { payment_id, status: "captured", provider: "zip", amount: 12000, currency: "USD", order_id: "order_123", plan? }
FieldMeaning
payment_idCoverPay payment id; it is also in your webhooks.
statuscaptured or authorized: the shopper's plan went through.
order_idYour order id from the link token. Check it matches the order you are completing.
planOnly for provider: "coverpay": the 4-payment schedule and your payout.
Exchanging again is safe
If your server loses the answer (timeout, crash), exchange the same public token again: you get the same payment back, and no money moves. Other businesses can't exchange your tokens. Public tokens expire after 30 minutes.

5. Listen for webhooks

Register an endpoint for session.captured and session.authorized. When one arrives, read the payment back with your key and mark the order paid. That also covers shoppers who close their browser before your page hears back. See Webhooks.

Next