StripeService
core/services/stripe_service.dart
Overview
Two-Dio service: one (DioHelper) for backend /vendor/stripe/* endpoints, one (_stripeDio) for direct calls to api.stripe.com using the publishable key. Covers payout account get/create, bank token + add, file upload + verify identity, account/balance/transactions.
User Flow
- Backend reads/writes go through DioHelper → auth interceptor attaches the seller token.
- Stripe direct calls (tokens, file uploads) use _stripeDio with a Bearer header set to the publishable key.
- All methods carry a RequestTrace with feature='seller/stripe' or 'seller/balance'.
- Helpers (_assertSuccess) unify the throw path with friendly default messages.
Cases & Edge Cases
- getPayoutAccount swallows 404/400/403/401 and returns null — interpreted as 'no account yet'.
- uploadFileToStripe uses multipart/form-data; bytes are streamed from the chosen file path.
- getBalance / getTransactions catch every error and return null/empty list — keeps the screen renderable even when partial Stripe outages occur.
- Direct Stripe calls bypass DioHelper interceptors — no auto-retry, no logging interceptor.
Code References
- lib/src/core/services/stripe_service.dart:17 // StripeService
- lib/src/core/services/stripe_service.dart:43 // getPayoutAccount
- lib/src/core/services/stripe_service.dart:77 // getStripeAccountToken
- lib/src/core/services/stripe_service.dart:127 // createPayoutAccount
- lib/src/core/services/stripe_service.dart:152 // getStripeBankToken
- lib/src/core/services/stripe_service.dart:210 // uploadFileToStripe
- lib/src/core/services/stripe_service.dart:286 // getBalance
- lib/src/core/services/stripe_service.dart:314 // getTransactions
API Calls
- GET
/vendor/stripe/payout-accountno statusRead the current Stripe Connect payout account state.
ResponsePayoutAccountModel | null
Errors- ·404 / 400 / 403 / 401 are swallowed as null (treated as 'no account yet')
lib/src/features/seller/bank_account/views/bank_account_screen.dart // initial loadauth: seller bearer.
- POST
/vendor/stripe/payout-accountno statusSubmit Step 1 of onboarding: account_token from Stripe → backend creates the Connect account.
Request{ account_token: string /* ct_... */ }ResponsePayoutAccountModel
lib/src/features/seller/bank_account/views/bank_account_screen.dart // Step 1 submitauth: seller bearer.
- POST
/vendor/stripe/bank_accountno statusSubmit Step 2 of onboarding: bank_token from Stripe → backend attaches the bank account.
Request{ bank_token: string /* btok_... */ }Response{ ... }lib/src/features/seller/bank_account/views/bank_account_screen.dart // Step 2 submitauth: seller bearer.
- POST
/vendor/stripe/verify-identityno statusSubmit Step 3 of onboarding: front-of-document file id → backend submits identity to Stripe.
Request{ front_file_id: string /* file_... */ }Response{ ... }lib/src/features/seller/bank_account/views/bank_account_screen.dart // Step 3 submitauth: seller bearer.
- GET
/vendor/stripe/accountno statusRefresh the full Stripe account JSON after onboarding completes.
ResponseStripe account JSON | null
lib/src/features/seller/bank_account/views/bank_account_screen.dart // refresh after step 3auth: seller bearer.
- GET
/vendor/stripe/balanceno statusAvailable + pending balance in cents.
ResponseBalanceModel { available, pending /* cents */ } | nulllib/src/features/seller/balance/views/balance_screen.dartauth: seller bearer.
- GET
/vendor/stripe/transactionsno statusPaginated list of seller transactions.
Response{ transactions: TransactionModel[] }lib/src/features/seller/balance/views/balance_screen.dartauth: seller bearer.
- GET
/vendor/stripe/transactions/:idno statusTransaction detail (rendered in a bottom sheet).
ResponseTransactionDetailModel | null
lib/src/features/seller/balance/widgets/transaction_detail_sheet.dartauth: seller bearer.
- POST
https://api.stripe.com/v1/tokensno statusDirect Stripe call (Step 1): tokenize personal account details into an account token (ct_...).
Requestform-urlencoded: account[individual][first_name|last_name|email|phone|dob[day|month|year]], account[individual][address][line1|city|state|postal_code|country], account[business_type], account[tos_shown_and_accepted]='true'
Response{ id: 'ct_...' }lib/src/features/seller/bank_account/views/bank_account_screen.dart // Step 1, via stripe_service.dart:127auth: Bearer = STRIPE_PUBLISHABLE_KEY. Hits api.stripe.com directly.
- POST
https://api.stripe.com/v1/tokensno statusDirect Stripe call (Step 2): tokenize bank account details into a bank token (btok_...).
Requestform-urlencoded: bank_account[country|currency|account_holder_name|account_holder_type|account_number]
Response{ id: 'btok_...' }lib/src/features/seller/bank_account/views/bank_account_screen.dart // Step 2, via stripe_service.dart:152auth: Bearer = STRIPE_PUBLISHABLE_KEY.
- POST
https://files.stripe.com/v1/filesno statusDirect Stripe call (Step 3): upload identity document and receive a file_id.
RequestFormData({ file: File, purpose: 'identity_document' })Response{ id: 'file_...' }lib/src/features/seller/bank_account/views/bank_account_screen.dart // Step 3, via stripe_service.dart:210 // uploadFileToStripeauth: Bearer = STRIPE_PUBLISHABLE_KEY. Hits files.stripe.com.
Notes
Sharing a single class for direct-Stripe and backend-binding calls is convenient but fragile — separate them if Stripe rotates the publishable key shape.