Credits
Payments

Purchase credits

Initiates credit purchase via Stripe Checkout Session.

Purchase Process

┌─────────────────────────────────────────────────────────────┐
│  1. Client calls POST /credits/purchase                    │
│     with package_id, success_url, cancel_url               │
└─────────────────────────────────────────────────────────────┘
                      │
                      ▼
            ┌─────────────────────┐
            │ Verify package      │
            │ - Exists?           │
            │ - Active?           │
            │ - stripe_price_id?  │
            └─────────────────────┘
             │              │
    VALID    │              │      INVALID
             ▼              ▼
┌──────────────────┐  ┌──────────────────┐
│ Retrieve         │  │ Error 404/400    │
│ stripeCustomerId │  │                  │
│ from Better      │  │                  │
│ Auth             │  │                  │
└──────────────────┘  └──────────────────┘
             │
             ▼
┌──────────────────────────────┐
│ Create Stripe Checkout       │
│ Session with:                │
│ - customer_id                │
│ - price_id                   │
│ - metadata (tenant_id,       │
│   user_id, package_id)       │
│ - success_url                │
│ - cancel_url                 │
└──────────────────────────────┘
             │
             ▼
┌──────────────────────────────┐
│ Return checkout_url          │
│                              │
│ Client redirects to          │
│ Stripe Checkout              │
└──────────────────────────────┘
             │
             ▼
┌──────────────────────────────┐
│ User pays on Stripe          │
│                              │
│ Stripe sends webhook         │
│ checkout.session.completed   │
└──────────────────────────────┘
             │
             ▼
┌──────────────────────────────┐
│ Backend credits the credits  │
│ via webhook handler          │
└──────────────────────────────┘

Prerequisites

  • The user must have the owner role (no Stripe account for tenants)
  • The user must have a stripeCustomerId in 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_id configured

Validations

  • ✅ Validation of package_id (valid UUID)
  • ✅ URL validation (success_url and cancel_url must be valid URLs)
  • ✅ Verification that the package exists and is active
  • ✅ Verification that the package has a stripe_price_id
  • ✅ Retrieval of stripeCustomerId from Better Auth
  • ✅ Creation of Stripe Checkout Session with complete metadata

Stripe Metadata

The Stripe Checkout Session includes the following metadata for webhook processing:

{
  "tenant_id": "tenant_123",
  "user_id": "user_456",
  "package_id": "550e8400-e29b-41d4-a716-446655440000"
}

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 API key
  • 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

curl -X POST https://api.faireplace.com/v1/credits/purchase \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "package_id": "550e8400-e29b-41d4-a716-446655440000",
    "success_url": "https://app.faireplace.com/credits/success?session_id={CHECKOUT_SESSION_ID}",
    "cancel_url": "https://app.faireplace.com/credits/cancel"
  }'

Response:

{
  "checkout_url": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3d4e5f6...",
  "package_id": "550e8400-e29b-41d4-a716-446655440000",
  "package_name": "Pack Starter",
  "credits_amount": 1000,
  "price_cents": 2990
}

The user must then be redirected to checkout_url to complete payment.

post/credits/purchase

Request

  • Base URL: https://api.faireplace.com/api
  • URL: https://api.faireplace.com/api/credits/purchase
  • Auth: HTTP bearer

Request body

package_idstring uuid required

Identifier of the credit package to purchase.

The package must be active and have a configured stripe_price_id.

success_urlstring uri required

Redirect 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_urlstring uri required

Redirect 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.

Example request

{
  "package_id": "550e8400-e29b-41d4-a716-446655440000",
  "success_url": "https://app.fairplace.com/credits/success?session_id={CHECKOUT_SESSION_ID}",
  "cancel_url": "https://app.fairplace.com/credits/cancel"
}

Response

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_urlstring uri required

Stripe 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_idstring uuid required

Identifier of the selected package.

package_namestring required

Name of the selected package.

credits_amountinteger required

Number of credits that will be credited after successful payment (in cents).

price_centsinteger required

Package price in euro cents.

Example response

{
  "checkout_url": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3d4e5f6...",
  "package_id": "550e8400-e29b-41d4-a716-446655440000",
  "package_name": "Pack Starter",
  "credits_amount": 1000,
  "price_cents": 2990
}

Changes

No recorded changes to this operation across all 1 revision of this API.