Credit system management.
Credits allow owners to pay for platform services (e.g., lease signing) without having to enter their payment information each time.
Features
- Purchase credits via Stripe Checkout Session
- Check credit balance
- Transaction history (purchases, consumption)
- List available packages
Restrictions
- Only users with the owner role can purchase credits
- Credits are isolated by tenant (multi-tenant)
Create a payment intent for a lease
Creates a payment intent for a lease (signing fees, etc.).
Supported methods:
- stripe: creates a Stripe PaymentIntent; the response contains
client_secretfor Stripe Elements (web). - credit: debits the user's credit balance; the response may contain
balance_after.
Prerequisites:
- The lease must exist (otherwise 404).
LeasesWritepermission required.- For credits: sufficient balance (otherwise 422 business error).
path Parameters
lease_idLease ID
Create a payment intent for a lease › Request Body
amountAmount in cents (e.g. 2990 = 29.90 EUR).
currencyCurrency code (e.g. "eur", "EUR").
payment_methodPayment method for a lease.
stripe: card payment via Stripe (PaymentIntent)credit: debit from the user's credit balance
Optional metadata propagated to the payment port.
The backend automatically adds lease_id and reason (e.g. "lease_payment").
Create a payment intent for a lease › Responses
Payment intent created successfully
payment_intent_idStripe PaymentIntent ID (e.g. "pi_xxx") or credit transaction ID.
statusPayment status.
amountAmount in cents.
currencypayment_methodPayment method for a lease.
stripe: card payment via Stripe (PaymentIntent)credit: debit from the user's credit balance
client_secretClient secret for Stripe Elements (web). Absent for credit payments.
balance_afterCredit balance after consumption (only if payment_method = credit).
Purchase credits
Initiates credit purchase via Stripe Checkout Session.
Purchase Process
Code
Prerequisites
- The user must have the owner role (no Stripe account for tenants)
- The user must have a
stripeCustomerIdin Better Auth- If absent, error 400: "You must have a Stripe account to purchase credits"
- The package must be active and have a
stripe_price_idconfigured
Validations
- ✅ Validation of
package_id(valid UUID) - ✅ URL validation (
success_urlandcancel_urlmust be valid URLs) - ✅ Verification that the package exists and is active
- ✅ Verification that the package has a
stripe_price_id - ✅ Retrieval of
stripeCustomerIdfrom Better Auth - ✅ Creation of Stripe Checkout Session with complete metadata
Stripe Metadata
The Stripe Checkout Session includes the following metadata for webhook processing:
Code
This metadata allows the webhook to credit the right user in the correct tenant after successful payment.
Error Handling
- 400 Bad Request: Invalid package, invalid URLs, or no Stripe account
- 401 Unauthorized: Invalid or expired JWT token
- 403 Forbidden: User is not an owner
- 404 Not Found: Package not found or inactive
- 500 Internal Server Error: Error creating the Checkout Session
Usage Example
Code
Response:
Code
The user must then be redirected to checkout_url to complete payment.
Purchase credits › Request Body
package_idIdentifier of the credit package to purchase.
The package must be active and have a configured stripe_price_id.
success_urlRedirect URL after successful payment.
The user will be redirected to this URL after completing the payment on the Stripe Checkout page.
Recommendations:
- Include a success parameter to identify the transaction
- Example:
https://app.fairplace.com/credits/success?session_id={CHECKOUT_SESSION_ID}
cancel_urlRedirect URL if the user cancels the payment.
The user will be redirected to this URL if they close the Stripe Checkout page without completing the payment.
Purchase credits › Responses
Purchase session created successfully.
The user must be redirected to checkout_url to complete payment.
Credits will be automatically credited after successful payment via webhook.
checkout_urlStripe Checkout page URL.
Required action: Redirect the user to this URL to complete the payment.
This URL is valid for a limited time (typically 24 hours). If the user does not complete the payment within this period, the session expires.
package_idIdentifier of the selected package.
package_nameName of the selected package.
credits_amountNumber of credits that will be credited after successful payment (in cents).
price_centsPackage price in euro cents.
Get credit balance
Retrieves the current credit balance of the authenticated user.
Behavior
- If the user has never had credits, returns a balance of 0 (no 404 error)
- The balance is always expressed in euro cents
- The currency is always EUR for now
Multi-Tenant Isolation
The returned balance is automatically filtered by:
tenant_idextracted from the JWTuser_idextracted from the JWT (claimsub)
A user can only see their own balance, and only within their tenant.
Balance Format
The balance is returned in cents:
5000= 50.00 EUR of available credits2990= 29.90 EUR of available credits0= No credits available
Usage Example
Code
Response:
Code
Get credit balance › Responses
Balance retrieved successfully.
Always returns a balance (0 if the user has never had credits).
balanceCredit balance in euro cents.
Examples:
5000= 50.00 EUR in credits2990= 29.90 EUR in credits0= No credits available
currencyBalance currency (always "EUR" for now).
last_updatedDate and time of the last balance update (ISO 8601).
Format: YYYY-MM-DDTHH:mm:ssZ
Get transaction history
Retrieves the credit transaction history of the authenticated user with pagination.
Pagination
Transactions are returned with pagination:
- limit: Maximum number of transactions to return (default: 50, max: 100)
- offset: Number of transactions to skip (default: 0)
Transactions are sorted by creation date descending (most recent first).
Transaction Types
Transactions can be of different types:
purchase: Credit purchase via Stripeconsumption: Credit consumption for a paymentexpiration: Credit expiration (if applicable)refund: Credit refundadjustment: Manual adjustment by an administrator
Amount Format
Amounts are in cents:
- Positive amount for purchases and additions
- Negative amount for consumptions
Multi-Tenant Isolation
The returned transactions are automatically filtered by:
tenant_idextracted from the JWTuser_idextracted from the JWT (claimsub)
A user can only see their own transactions, and only within their tenant.
Usage Example
Code
Response:
Code
query Parameters
limitMaximum number of transactions to return.
- Default:
50 - Maximum:
100 - Minimum:
1
offsetOffset for pagination (number of transactions to skip).
- Default:
0 - Minimum:
0
Get transaction history › Responses
Transaction history retrieved successfully.
Always returns an array (empty if the user has never had transactions).
List of transactions, sorted by creation date descending (most recent first).
totalTotal number of transactions returned in this response.
Note: This is not the total number of user transactions, but only the count returned in this page.
limitMaximum number of requested transactions.
Default value: 50
Maximum: 100
offsetOffset for pagination (number of transactions to skip).
Default value: 0
List available credit packages
Retrieves the list of credit packages available for purchase for the tenant.
Filtering
By default, only active packages are returned.
To include inactive packages, use active_only=false.
Sorting
Packages are sorted by:
display_orderascending (configured display order)- Creation date ascending (in case of
display_ordertie)
Multi-Tenant Isolation
The returned packages are automatically filtered by:
tenant_idextracted from the JWT
Each tenant can have its own configured credit packages.
Prerequisites for Purchase
For a package to be purchasable, it must:
- Be active (
active: true) - Have a stripe_price_id configured
- Belong to the user's tenant
Usage Example
Code
Response:
Code
query Parameters
active_onlyFilter only active packages.
- Default:
true(only active packages are returned) - false: Also include inactive packages
Inactive packages cannot be purchased but may be visible for traceability or administration purposes.
List available credit packages › Responses
Package list retrieved successfully.
Always returns an array (empty if no packages are configured for the tenant).
List of packages, sorted by display_order ascending, then by creation date.