Skip to main content

Phase 4 — Payment

The payment flow via RideNDine → Stripe. COOCO does not handle money directly — it only initiates the payment session and updates status from webhooks (not from client callbacks).


Overview

COOCO → RideNDine → Stripe ← Customer
↓ (webhook)
COOCO (update status)
StepFromToAction
4.1COOCORideNDinePOST /payment/process
4.2RideNDineStripeCreate PaymentIntent
4.3StripeRideNDinePaymentIntent response
4.4RideNDineCOOCOResponse POST /payment/process
4.5CustomerStripeStripe checkout form
4.6StripeRideNDinePOST /api/webhooks/stripe
4.7RideNDineCOOCOPOST /webhooks/payment-result

Step 4.1 — Initiate Payment

From: COOCO → To: RideNDine

Endpoint: POST /payment/process

Called via Directus Extension: POST /ridendine/checkout or /ridendine/payment.

Request Body

{
"ridendine_order_id": "<orders.ridendine_order_id>",
"external_order_id": "<orders.id>",
"amount_cents": "<total_cents>",
"currency": "USD",
"return_url": "<success_url>",
"cancel_url": "<cancel_url>"
}

Step 4.2 — Create PaymentIntent (RideNDine Internal)

RideNDine initiates a PaymentIntent on Stripe. COOCO does not participate in this step.


Step 4.3 — Stripe Response (RideNDine Internal)

Stripe returns client_secret / status to RideNDine. COOCO does not participate.


Step 4.4 — Receive Payment Session

From: RideNDine → To: COOCO

Purpose: COOCO receives the information needed to display the Stripe payment form.

Response

{
"client_secret": "<stripe_client_secret>",
"checkout_url": "<optional_hosted_url>",
"payment_intent_id": "<pi_...>"
}

Processing

  • Save orders.payment_intent_id
  • Pass client_secret to cookin-web to embed Stripe UI Elements

Step 4.5 — Customer Completes Payment

From: Customer → To: Stripe

Customer interacts directly with the Stripe checkout form. COOCO does not send anything at this step.


Step 4.6 — Stripe Webhook (RideNDine Internal)

Stripe calls POST /api/webhooks/stripe on RideNDine to confirm payment_succeeded / payment_failed. COOCO does not participate.


Step 4.7 — Webhook: Payment Result

From: RideNDine → To: COOCO

Endpoint (COOCO expose): {DIRECTUS_URL}/ridendine/webhooks/payment-result

Method: POST

Purpose: COOCO updates to PAID / FAILED — trusts only the webhook, not the client callback.

Received Payload

{
"event_id": "<uuid>",
"event": "payment.succeeded | payment.failed",
"external_order_id": "<orders.id>",
"payment_intent_id": "<pi_...>",
"paid_at": "<ISO8601>"
}

Processing on payment.succeeded

  • orders.payment_status = PAID
  • orders.status = PENDING_CHEF_APPROVAL
  • Log to integration_events with event_id (idempotency)
danger

DO NOT set PAID when the user clicks the "Pay" button. Only set it upon receiving this webhook from RideNDine.