Skip to main content

USD Integration Flow

For Echezona and partner teams, the recommended pattern is:

  • Single server call to Clive checkout-intent
  • Client-side Stripe Payment Element confirmation
  • Clive transaction orchestration + partner webhook finalization

This aligns directly with:

  • POST /transactions/checkout-intent

Step-by-step sequence

1) Create checkout intent in Clive

Call POST /transactions/checkout-intent from your backend.

Clive will:

  • initialize the transaction
  • create Stripe PaymentIntent
  • attach the intent internally
  • return clive_tx_id, stripe_payment_intent_id, and client_secret

Persist:

  • clive_tx_id
  • stripe_payment_intent_id
  • client_secret (short-lived, for frontend use)
  • your immutable reference (echezona_reference)
  • your optional meta object
  • chosen statement_descriptor_suffix

2) Confirm payment in frontend

Use Stripe Payment Element and the client_secret.

Frontend engineers should follow this sequence exactly:

  1. Receive client_secret, stripe_publishable_key, and clive_tx_id from your backend.
  2. Initialize Stripe with loadStripe(stripe_publishable_key).
  3. Render <Elements options={{ clientSecret }}>.
  4. Render <PaymentElement /> inside your checkout form.
  5. On submit, call elements.submit() first.
  6. Then call stripe.confirmPayment({ elements, confirmParams, redirect: "if_required" }).
  7. If no Stripe error, refresh status for clive_tx_id and display final order state.

Recommended confirmation call (same style as sandbox-web):

const result = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: window.location.href
},
redirect: "if_required"
});

if (result.error) {
// show result.error.message
} else {
// poll/fetch transaction status and render success
}

3) Handle final status with Clive status updates

  • Clive updates transaction status and computed fees.
  • Clive sends signed status notification to your webhook URL.

Do not mark orders as paid from frontend callback alone; only finalize after Clive status/webhook confirmation.

Sequence diagram

Echezona Backend -> Clive: POST /transactions/checkout-intent
Clive -> Stripe: create PaymentIntent
Stripe -> Clive: payment_intent_id + client_secret (internal processing)
Clive -> Echezona Backend: clive_tx_id + payment_intent_id + client_secret (pending)
User + Echezona Frontend -> Stripe: confirm payment
Clive -> Echezona Webhook URL: signed transaction update

Example backend orchestration (pseudo-code)

// 1) Create checkout intent on Clive
const checkout = await clive.createCheckoutIntent({
partner_id: "ECHEZONA001",
client_id: "AIRPEACE001",
amount: 750,
currency: "USD",
email: "buyer@example.com",
statement_descriptor_suffix: "AIRPEACE",
echezona_reference: "EZ12345",
meta: {
order_id: "ORD-1001",
customer_tier: "gold"
}
});

return {
clientSecret: checkout.client_secret,
cliveTxId: checkout.clive_tx_id,
stripePaymentIntentId: checkout.stripe_payment_intent_id
};

Example frontend checkout page (minimal)

<Elements stripe={stripePromise} options={{ clientSecret }}>
<form
onSubmit={async (e) => {
e.preventDefault();
await stripe.confirmPayment({
elements,
confirmParams: { return_url: window.location.href },
redirect: "if_required"
});
}}
>
<PaymentElement />
<button type="submit">Pay now</button>
</form>
</Elements>

Frontend checklist before shipping

  • Payment page mounts <PaymentElement /> only after backend returns client_secret.
  • Submit handler uses both elements.submit() and stripe.confirmPayment(...).
  • UI handles and displays Stripe errors cleanly.
  • Checkout page can resume/reconcile state using clive_tx_id.
  • Backend/webhook path, not frontend callback alone, marks the transaction as paid.

Operational best practices

  • Reuse the same idempotency-key when retrying the same business action.
  • Do not mark order paid based only on frontend callback; rely on webhook-confirmed success.
  • Verify X-Clive-Signature on incoming Clive webhooks.
  • Treat the webhook meta object as your round-tripped partner metadata from transaction initialization.
  • Use a dead-letter or retry queue for failed webhook processing on your side.
  • Re-fetch transaction status after confirmPayment so UI always reflects Clive final state.
  • Enforce a deterministic suffix convention (for example AIRPEACE, ECHEZONA AIR) and persist it per transaction for support/reconciliation.
  • Legacy integrations can still use /transactions/initialize + /transactions/attach-intent, but new integrations should use checkout-intent.