cimplify
Checkout integration

Drop-in checkout (hosted Pay)

The fastest path to a paid order: create a checkout session on your server, then redirect the customer to the URL it returns. Cimplify hosts the entire checkout UI at `pay.cimplify.io/s/<sessionId>` (auth, address, payment method, compliance). You get a webhook (or success-URL redirect) when payment lands.

Flow

1. Customer adds items to cart on your storefront.
2. Your server hits POST /v1/checkout/sessions with the cart_id and a secret key.
3. The API returns { id, url, status, expires_at }.
4. You 302 the customer to `url` (or open it in a popup).
5. Customer completes payment on pay.cimplify.io.
6. Cimplify redirects them to your success_url with ?order_id=... &session_id=...
   AND fires order.completed / payment.succeeded webhooks.

Create a session

Authenticate with a secret key (sk_…). The session is bound to whatever business that key belongs to.

cURL
curl https://api.cimplify.io/v1/checkout/sessions \
  -H "Authorization: Bearer $CIMPLIFY_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "cart_id": "crt_01J5...",
    "public_key": "pk_live_…",
    "success_url": "https://store.example.com/orders/thanks",
    "cancel_url":  "https://store.example.com/cart",
    "default_order_type": "delivery",
    "submit_label": "Pay GH₵29.99"
  }'

Request body

FieldTypeRequiredNotes
cart_idstringyesAn existing cart belonging to the same business as the API key.
public_keystringnoThe pk_… key to embed in the hosted page; defaults to the business's primary public key.
order_typesstring[]noSubset of delivery | pickup | dine_in. Defaults to whatever the business supports.
default_order_typestringnoPre-select an order type.
currencystringnoISO 4217. Defaults to the cart currency.
success_urlstringnoCimplify redirects here on success with order_id and session_id query params.
cancel_urlstringnoShown as a "Return to store" button on the hosted page.
appearanceobjectnoElementAppearance.
submit_labelstringnoOverride the Pay button copy.
metadataobjectnoFree-form JSON echoed on the resulting order.

Response

{
  "id": "cs_01J5BGM...",
  "url": "https://pay.cimplify.io/s/cs_01J5BGM...",
  "status": "open",
  "expires_at": "2026-05-07T17:00:00Z"
}

Redirect the customer

Next.js Route Handler
// app/api/checkout/route.ts
import { redirect } from "next/navigation";

export async function POST(request: Request) {
  const { cartId } = await request.json();

  const r = await fetch("https://api.cimplify.io/v1/checkout/sessions", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.CIMPLIFY_SECRET_KEY!}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      cart_id: cartId,
      success_url: `${process.env.STORE_URL}/orders/thanks`,
      cancel_url:  `${process.env.STORE_URL}/cart`,
    }),
  });

  if (!r.ok) {
    return Response.json({ error: await r.text() }, { status: 500 });
  }

  const { url } = await r.json() as { url: string };
  redirect(url);
}

Reading the success redirect

Cimplify appends order_id and session_id to your success_url. Treat the redirect as a UI hint only; the source of truth is the webhook. Don't fulfill orders from the redirect alone.

app/orders/thanks/page.tsx
export default async function ThanksPage({
  searchParams,
}: {
  searchParams: Promise<{ order_id?: string; session_id?: string }>;
}) {
  const { order_id } = await searchParams;
  if (!order_id) return <p>Awaiting confirmation…</p>;

  const r = await getServerClient().orders.get(order_id);
  if (!r.ok) return <p>Order not found.</p>;

  return <h1>Thanks! Order #{r.value.order_number}</h1>;
}

Webhooks

Wire the order.completed and payment.succeeded events to your fulfillment system. See webhooks for signing and replay.

Session status

StatusMeaning
openCustomer has not completed yet. URL is usable.
completedPayment captured; an order exists.
expiredPast expires_at. Issue a new session.

Next

On this page