Skip to content

Running the platform

Payments

Sharkhex Delivery currently provides a Stripe-based payment implementation.

Officially supported payment provider

The supported live payment provider is:

Stripe

Stripe is used for:

  • Customer creation.
  • SetupIntents.
  • Saved card payment methods.
  • PaymentIntents.
  • Webhook verification.
  • Apple Pay through Stripe.
  • Google Pay through Stripe.

The admin area includes a Payment Providers section and may display provider examples such as Stripe, Adyen, or PayPal. At code level, Stripe is the implemented provider. Additional providers require custom development.

Supported customer payment methods

The platform can support these payment methods depending on backend configuration, mobile app configuration, and regional availability:

  • Card payments through Stripe.
  • Saved cards through Stripe SetupIntents.
  • Apple Pay through Stripe.
  • Google Pay through Stripe.
  • Cash or offline-style payment methods where enabled by business rules.

Apple Pay and Google Pay are not separate payment processors in this project. They are wallet payment methods processed through Stripe.

Backend Stripe settings

Configure backend Stripe credentials from the admin panel, not from .env files. Go to Payment Settings and fill in the Stripe publishable key, secret key, and webhook secret.

The backend setting keys used by the payment service are:

payments.stripe.public_key
payments.stripe.secret_key
payments.stripe.webhook_secret

Mobile Stripe settings

Configure the mobile app with the same Stripe account publishable key:

EXPO_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_or_live_xxx

For Apple Pay, update the merchant identifier in:

app.config.ts

Example:

merchant.com.yourcompany.yourapp

Stripe webhook

Create a Stripe webhook endpoint pointing to:

https://your-domain.com/api/v1/webhook/stripe

Then copy the webhook signing secret into Payment Settings in the backend admin panel.

Customer payment flow

  1. Customer selects products and creates an order.

  2. Customer chooses a payment method in the mobile checkout.

  3. The app calls:

    POST /api/v1/orders/{id}/pay
  4. The backend creates or updates the Stripe PaymentIntent.

  5. The app confirms the payment when required.

  6. Stripe sends webhook events to the backend.

  7. The backend updates payment and order state.

Saved card flow

  1. The app requests a SetupIntent:

    POST /api/v1/users/setup-intent
  2. The app collects card details using Stripe React Native.

  3. Stripe attaches the card to the customer.

  4. Saved methods can be listed with:

    GET /api/v1/users/payment-methods
  5. A saved method can be removed with:

    DELETE /api/v1/users/payment-methods/{paymentMethodId}

Test mode

Use Stripe test keys while developing:

pk_test_xxx
sk_test_xxx

Use live keys only after completing payment testing, webhook testing, and mobile wallet setup.

Paying riders and vendors

Customers always pay the platform. Each rider and vendor has a wallet that is credited with their share (vendor earnings, delivery pay, tips) and debited for refunds and for cash-on-delivery money they still hold. Payout runs pay the net balance; the platform's commission is what is never paid out.

Choose how each payee type is paid in Payment Settings:

payments.payouts.rider_method   bank_transfer | stripe_connect
payments.payouts.vendor_method  bank_transfer | stripe_connect

Bank transfer (default): riders and vendors enter their IBAN in the app under Profile → Payouts. An admin verifies it under Wallets → Verify bank details; any change sends it back for review. Payout runs create pending payouts; under Payouts, export the pending bank transfers as CSV, pay them from the platform bank account, then mark them paid.

Stripe Connect: riders and vendors complete Stripe's hosted onboarding from the app and receive their payouts as Stripe transfers. Activate Connect in the Stripe dashboard, set platform.public_url, add a webhook endpoint for events on connected accounts (account.updated) pointing to the same webhook URL, put its signing secret in payments.stripe.connect_webhook_secret, and set the platform's own Stripe payout schedule to manual so the balance is available for transfers.

Payout runs are cron jobs (riders weekly, vendors on the 1st and 16th); see Scheduled jobs. Admins can also start one from Payouts → Run payouts now.

Receipts, invoices and credit notes

Every paid order and parcel booking gets a numbered receipt (card orders when paid, cash orders when the rider collects). The receipt names the store as the seller of the products and the platform as the seller of the delivery and service fees. Customers who add company details in the app (Profile → Invoice details) also get an invoice for the platform's fees; the store invoices its own products. Refunds produce credit notes. Customers open them from the order or parcel screen and from the confirmation/receipt email; admins see all of them under Receipts & invoices, with a CSV export for accounting.

Before going live, fill in these settings so they print on every document:

platform.legal_name, platform.tax_id, platform.registration_number, platform.legal_address   (General settings)
platform.timezone          local time printed on documents, e.g. Europe/Bucharest
invoicing.number_prefix    e.g. ACME → ACME-R-2026-000001 (receipts), ACME-I-… (invoices), ACME-C-… (credit notes)
platform.public_url        base URL of the links in emails

A partial refund (for a reported problem) gets its own credit note: for the refunded items, plus a proportional share of every taxed line for any amount beyond them. Cancelling an order that was already partly refunded gives back only the rest, with a credit note for it.

Stores need their legal name, tax ID and tax rate on their vendor record. Numbers are gap-free per series and year, and an issued document never changes. If documents are ever missing (for example for orders paid before this feature), run php bin/console app:issue-fiscal-documents.

Found a mistake? Tell us.