arch-atlas

Cart Service (Medusa Store API)

core/services/cart_service.dart

data

Overview

Dio-backed client for every cart-shaped endpoint Medusa exposes: create cart (physical vs provision), get/update cart, add/update line items, shipping options + methods, promo codes, payment collections (full and partial), and complete cart.

User Flow

  1. createPhysicalCart / createProvisionCart POST /store/carts with metadata.type and an optional region_id; the metadata is what lets the UI keep marketplace and booking carts separate.
  2. addItemToCart / updateCartItem mutate line items (qty=0 deletes server-side).
  3. applyPromoCode / removePromoCode use POST … /promotions with the new full list (Medusa-style overwrite semantics).
  4. fetchShippingOptions + addShippingMethod attach a delivery option.
  5. fetchPaymentProviders + createPaymentCollection + createPaymentSession build the Stripe path.
  6. createPartialPaymentSession splits the amount between Stripe (deposit) and 'pp_system_default' (pay-on-site rest) for booking deposits.
  7. completeCart converts the cart to an order_set after a successful payment.

Cases & Edge Cases

  • create*Cart auto-retries without region_id on 400/422 — backend rejects unknown 'region_id' for some merchant configs; the retry lets the cart still be created.
  • Booking-question helpers (getCartItemQuestions / answer / remove) treat 404 as 'no questions configured' rather than an error.
  • completeCart accepts three possible shapes (order_set, data, {type:'order'}) because the Medusa response varies by version — the priority order matters.
  • removePromoCode currently sends an empty promo_codes list rather than the documented DELETE endpoint; backend behavior has changed across Medusa V2 minors.

Code References

  • lib/src/core/services/cart_service.dart:7 // CartService
  • lib/src/core/services/cart_service.dart:11 // createProvisionCart (+retry)
  • lib/src/core/services/cart_service.dart:185 // addItemToCart
  • lib/src/core/services/cart_service.dart:378 // applyPromoCode
  • lib/src/core/services/cart_service.dart:612 // createPartialPaymentSession
  • lib/src/core/services/cart_service.dart:663 // completeCart

API Calls

  • POST/store/cartsno status

    Create a fresh Medusa cart of a given type (provision or physical).

    Request
    { metadata: { type: 'provision' | 'physical' }, region_id?: string }
    Response
    { cart: { id: string } }
    lib/src/features/shared/checkout/views/checkout_screen.dart // initCheckout

    auth: customer. Called once on checkout entry to promote the local cart to a server cart.

  • GET/store/carts/:cartIdno status

    Fetch the current server-side cart (lines, totals, addresses, promotions).

    Response
    { cart: Cart }
    lib/src/features/shared/cart/views/cart_screen.dart + checkout_screen.dart

    auth: customer.

  • POST/store/carts/:cartId/line-itemsno status

    Add a line item to the cart.

    Request
    { variant_id: string, quantity: number }
    Response
    { cart: Cart }
    lib/src/features/shared/product_details/views/product_details_screen.dart // add-to-cart

    auth: customer.

  • POST/store/carts/:cartId/line-items/:lineItemIdno status

    Update or delete (quantity=0) a line item.

    Request
    { quantity: number /* 0 deletes */ }
    Response
    { cart: Cart }
    lib/src/features/shared/cart/views/cart_screen.dart

    auth: customer.

  • POST/store/carts/:cartIdno status

    Patch arbitrary cart fields (shipping address, email, region…).

    Request
    Caller-provided map, e.g. { shipping_address, email }
    Response
    { cart: Cart }
    lib/src/features/shared/checkout/views/checkout_screen.dart

    auth: customer.

  • GET/store/shipping-options?cart_id=:idno status

    List shipping options available for the cart's destination + items.

    Response
    { shipping_options: ShippingOption[] }
    lib/src/features/shared/checkout/views/widgets/checkout_shipping_options.dart

    auth: customer.

  • POST/store/carts/:cartId/shipping-methodsno status

    Attach a chosen shipping method to the cart.

    Request
    { option_id: string }
    Response
    { cart: Cart }
    lib/src/features/shared/checkout/views/widgets/checkout_shipping_options.dart

    auth: customer.

  • POST/store/carts/:cartId/promotionsno status

    Apply or clear promo codes on the cart.

    Request
    { promo_codes: string[] /* empty array clears */ }
    Response
    { cart: Cart }
    lib/src/features/shared/cart/views/cart_screen.dart

    auth: customer. Removal currently uses empty-array semantics, not the documented DELETE endpoint.

  • GET/store/payment-providers?region_id=:idno status

    List payment providers configured for the cart's region.

    Response
    { payment_providers: PaymentProvider[] }
    lib/src/features/shared/checkout/views/widgets/checkout_payment_methods.dart

    auth: customer.

  • POST/store/payment-collectionsno status

    Create a payment collection for the cart.

    Request
    { cart_id: string }
    Response
    { payment_collection: { id: string, amount: number } }
    lib/src/features/shared/checkout/views/checkout_screen.dart

    auth: customer.

  • POST/store/payment-collections/:idno status

    Resync the amount on an existing payment collection (e.g. after cart change).

    Request
    { amount: number }
    Response
    { payment_collection: PaymentCollection }
    lib/src/features/shared/checkout/views/checkout_screen.dart

    auth: customer.

  • POST/store/payment-collections/:id/payment-sessionsno status

    Initialize a payment session with a chosen provider; returns the Stripe client_secret.

    Request
    { provider_id: string }
    Response
    { payment_collection: { payment_sessions: [{ provider_id, data: { client_secret } }] } }
    lib/src/features/shared/checkout/views/checkout_screen.dart

    auth: customer.

  • POST/store/payment-collections/:id/partial/payment-sessionno status

    Multi-session partial payment for booking deposits (e.g. deposit + remainder).

    Request
    { providers: [{ provider_id: 'pp_partial_stripe-connect' | 'pp_system_default', amount: number }] }
    Response
    { payment_collection: PaymentCollection }
    lib/src/features/shared/checkout/views/checkout_screen.dart // booking deposits

    auth: customer. Used only on bookings that allow a partial-payment policy.

  • POST/store/carts/:cartId/set-orderno status

    Complete the cart and convert it into an order.

    Response
    { order_set?: OrderSet, data?: any, order?: Order } /* shape varies by Medusa version */
    lib/src/features/shared/checkout/views/checkout_screen.dart // Pay → completeCart

    auth: customer. Three response shapes accepted (order_set → data → order) — priority order matters.

  • GET/store/carts/:cartId/line-items/:lineItemId/questionsno status

    Fetch booking-questions for a provision line item.

    Response
    { questions: BookingQuestion[] }
    Errors
    • ·404 — no questions defined for this line item
    lib/src/features/shared/cart/views/cart_screen.dart, checkout_booking_questions.dart

    auth: customer.

  • POST/store/carts/:cartId/line-items/:lineItemId/questions/:questionIdno status

    Persist a customer's answer to a booking question (option / comment / number / image).

    Request
    { selected_option_ids?: string[], comment?: string, number?: number, image_file_id?: string }
    Response
    200 / 201 (no body)
    lib/src/features/shared/checkout/views/widgets/checkout_booking_questions.dart

    auth: customer.

  • DELETE/store/carts/:cartId/line-items/:lineItemId/questions/:questionIdno status

    Clear an answer to a booking question.

    Response
    200 (no body)
    lib/src/features/shared/checkout/views/widgets/checkout_booking_questions.dart

    auth: customer.

Notes

Every method opts in to authScope: 'customer' via RequestTrace; never call this with a seller-only token attached.