Urban Store processes payments through Stripe using the PaymentIntents API. All transactions are denominated in Colombian Peso (COP). The integration is intentionally minimal: there are no webhooks — the frontend drives the full payment lifecycle via two API calls bookending the Stripe-hosted card collection step. Stripe’sDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/ALEJ4NDRO2025/urban-store/llms.txt
Use this file to discover all available pages before exploring further.
payment_intent_id is stored on the order document for audit and reconciliation purposes.
Payment Flow
Create PaymentIntent
The frontend calls Response:
POST /api/payments/create-payment-intent/ with the order_id. The backend validates that the order belongs to the authenticated user and is still in pending status, then creates a Stripe PaymentIntent for order.total × 100 centavos in cop currency. The payment_intent_id is saved on the order document and the client_secret is returned to the frontend.Frontend Collects Card Details
Using the
client_secret, the frontend mounts Stripe’s <PaymentElement> component (from @stripe/react-stripe-js). The customer enters their card details directly in the Stripe-hosted UI — card data never touches Urban Store’s servers.Stripe Processes the Payment
The frontend calls
stripe.confirmPayment() (or stripe.confirmCardPayment()) with the client_secret. Stripe validates the card, charges it, and transitions the PaymentIntent to succeeded (or returns an error).Confirm Payment with Backend
The frontend calls Response (success):Response (not yet completed):
POST /api/payments/confirm-payment/ with both order_id and payment_intent_id. The backend retrieves the PaymentIntent from Stripe and checks its status. If succeeded, the order is updated to paid and paid_at is set. The expires_at field is cleared (None) so the order is no longer subject to TTL cancellation.Currency and Amount Conversion
All PaymentIntents are created incop (Colombian Peso). Stripe requires amounts in the smallest currency unit (centavos), so the order total is multiplied by 100:
The Stripe
metadata field carries the order_id, which is useful for manual reconciliation or future webhook integration. It is not used programmatically by the current backend.Order Validation
Before creating a PaymentIntent, the backend enforces two conditions:- Ownership — the order must exist and its
user_idmust match the email extracted from the JWT. Orders belonging to other users return404. - Status — the order must be in
pendingstatus. Any other status (includingpaid,cancelled, orshipped) returns400with"La orden ya fue procesada".
Frontend Libraries
The frontend uses the official Stripe React integration:| Package | Version |
|---|---|
@stripe/react-stripe-js | ^6.2.0 |
@stripe/stripe-js | ^9.2.0 |
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY, and the Django backend requires STRIPE_SECRET_KEY in its settings.
Error Handling
Anystripe.error.StripeError raised during PaymentIntent creation or retrieval is caught and returned as a 400 Bad Request:
Test Card
During development, use Stripe’s standard test card to simulate a successful payment:| Field | Value |
|---|---|
| Card number | 4242 4242 4242 4242 |
| Expiry | Any future date (e.g. 12/30) |
| CVC | Any 3 digits (e.g. 123) |
| ZIP | Any value |