USD Integration Flow
Recommended integration path
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/initializePOST /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_idstripe_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-keywhen retrying the same business action. - Do not mark order paid based only on frontend callback; rely on webhook-confirmed success.
- Verify
X-Clive-Signatureon incoming Clive webhooks. - Use a dead-letter or retry queue for failed webhook processing on your side.
- Re-fetch transaction status after
confirmPaymentso UI always reflects Clive final state. - Enforce a deterministic suffix convention (for example
AIRPEACE,ECHEZONA AIR) and persist it per transaction for support/reconciliation.