Agapi Platform Documentation
Central Backend Engine

Payments and Stripe

Why company-specific payment accounts exist and how invoices, subscriptions, fuel charges, and provider updates work.

The payment service turns an agreed business amount into a request for money and then brings the later Stripe result back into Agapi.

It does not decide every price. Booking, fuel, membership, VAT, and balance rules provide the input; the payment service checks the customer/company context and performs the provider operation.

Why each company has its own Stripe context

Agapi can operate through more than one legal company. Each company can have its own Stripe secret, tax settings, and account tax identifiers.

Every payment request therefore needs a company ID. The service uses it to choose the client and does not intentionally fall back to another company's credentials. Missing configuration is an error because charging through the wrong legal entity would be worse than stopping the request.

Stripe customer records

One Agapi member can need a Stripe customer in more than one company account. The member record keeps the Stripe ID by company.

Before creating an invoice or subscription, the service:

  1. loads the local member and company inside the current staff scope;
  2. checks whether the saved Stripe customer still exists for that company;
  3. creates or updates the Stripe customer when needed;
  4. saves the company-specific provider ID back to the member.

This prevents a member from being silently charged through a customer object that belongs to a different company.

Manual invoice

A manual invoice is used when staff have agreed one or more named items and need to send a payable invoice to the member.

The request contains company, member, currency, and item name/price/quantity. Optional item-specific VAT can be selected. Stripe creates the invoice and item prices, sends the invoice, and returns a hosted invoice URL. The member's local invoice information is then updated.

The configured collection method is send invoice. This is a payable invoice link, not an automatic off-session card charge.

Fuel invoice

A fuel invoice uses the supplied fuel quantity, final fuel cost, currency, company, member, description, and optional fuel VAT. Stripe creates and sends a separate invoice and returns its ID and hosted URL.

The service does not calculate the original fuel reading. If the amount looks wrong, check the trip readings, quantity, price, VAT choice, currency, and company before retrying the provider action.

Subscription

A subscription represents recurring membership billing. The request supplies a main recurring price, interval (day, week, month, or year), interval count, title, currency, optional VAT, and optional additional invoice items.

Stripe creates the subscription and finalizes the first invoice so the member can use its hosted payment page. Later Stripe events update the local membership and payment state.

Cancelling a subscription calls the company-specific Stripe account. If the direct cancellation response cannot be used, the service retrieves the current subscription and applies the cancellation handling from that provider state.

Cancellation

The cancel-invoice action supports two provider object types:

  • a PaymentIntent ID is cancelled as a payment intent;
  • another invoice ID is voided as an invoice.

Voiding an invoice and cancelling a subscription are separate operations. Staff must choose the action that matches the business decision.

Provider updates (webhooks)

Stripe sends later events because payment can complete after the original API request returned.

flowchart LR
    A[Invoice, booking payment, or subscription created] --> B[Member acts in Stripe]
    B --> C[Stripe sends event]
    C --> D{Known event type?}
    D -- Yes --> E[Find local member, booking, invoice, or subscription]
    E --> F[Update local state and create related messages]
    D -- No --> G[Reject as unsupported and investigate]

The handler supports:

  • successful invoice payment;
  • successful payment intent for a booking;
  • voided invoice;
  • subscription created, updated, or deleted.

Invoice-payment success is then separated into fuel, subscription, manual invoice, or other known metadata paths. Metadata is therefore part of the business link between Stripe and the local record.

Partial failures and safe recovery

SituationRiskSafe first action
Stripe object exists, local screen failedRetrying may create another invoice/subscription.Find the provider object by company/customer and compare its ID and metadata.
Local record exists, Stripe call failedLocal state may imply work that provider never accepted.Check logs and provider account before changing the record.
Payment succeeded, local state unchangedWebhook may be missing, unsupported, or failed.Find the event and run the approved replay/recovery path.
Wrong VAT or currencyThe request may have selected the wrong company/region/rate.Correct the source configuration; do not edit a paid historical amount.
Cancellation appears incompleteInvoice and subscription may both exist.Check each provider object separately.

Keep Stripe IDs and event evidence. Deleting them makes reconciliation harder.

Technical reference

Admin payment routes are under /api/v1/payments: send invoice, send fuel invoice, cancel invoice, create/cancel subscription, webhook, available currencies, and subscription intervals. The provider implementation is Shared\Service\Payment\StripeService; request shapes are the payment DTOs used by PaymentController.

On this page