Skip to main content

USD Integration Flow

For Echezona and partner teams, the recommended pattern is:

  • Server-side Stripe PaymentIntent creation
  • Client-side Stripe Payment Element confirmation
  • Clive transaction orchestration + webhook finalization

This aligns directly with:

  • POST /transactions/initialize
  • POST /transactions/attach-intent
  • Stripe -> POST /webhooks/stripe (to Clive)

Step-by-step sequence

1) Initialize in Clive

Call POST /transactions/initialize as soon as your checkout starts.

Persist:

  • clive_tx_id
  • your echezona_reference

2) Create Stripe PaymentIntent

In your backend:

  • create PaymentIntent with Stripe secret key
  • set statement_descriptor_suffix (partner-owned responsibility)
  • include your merchant/order metadata
  • keep amount/currency aligned with Clive payload

Persist:

  • Stripe payment_intent.id
  • Stripe client_secret
  • chosen statement_descriptor_suffix

3) Attach Stripe intent to Clive transaction

Call POST /transactions/attach-intent using:

  • clive_tx_id
  • stripe_payment_intent_id

This changes Clive status to pending.

4) Confirm payment in frontend

Use Stripe Payment Element and the client_secret.

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
}

5) Handle final status with webhooks

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

Sequence diagram

Echezona Backend -> Clive: POST /transactions/initialize
Clive -> Echezona Backend: clive_tx_id (initialized)
Echezona Backend -> Stripe: create PaymentIntent
Stripe -> Echezona Backend: payment_intent_id + client_secret
Echezona Backend -> Clive: POST /transactions/attach-intent
Clive -> Echezona Backend: status pending
User + Echezona Frontend -> Stripe: confirm payment
Stripe -> Clive: POST /webhooks/stripe
Clive -> Echezona Webhook URL: signed transaction update

Example backend orchestration (pseudo-code)

// 1) Initialize on Clive
const initialized = await clive.initialize({
partner_id: "ECHEZONA001",
client_id: "AIRPEACE001",
amount: 750,
currency: "USD",
echezona_reference: "EZ12345"
});

// 2) Create Stripe PI
const pi = await stripe.paymentIntents.create({
amount: 75000, // cents
currency: "usd",
statement_descriptor_suffix: "AIRPEACE",
automatic_payment_methods: { enabled: true },
metadata: {
clive_tx_id: initialized.clive_tx_id,
partner_id: "ECHEZONA001",
client_id: "AIRPEACE001",
echezona_reference: "EZ12345"
}
});

// 3) Attach PI to Clive
await clive.attachIntent({
clive_tx_id: initialized.clive_tx_id,
stripe_payment_intent_id: pi.id
});

return { clientSecret: pi.client_secret, cliveTxId: initialized.clive_tx_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>

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.
  • 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.