FairePlace Payments API

Checkout sessions, payment status, and payment confirmation.

GitHub OpenAPI

Operations 1

POST /credits/purchase Purchase credits #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/faireplace-com:faireplace-com-payments-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

faireplace-com-payments-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: FairePlace Property Management Payments API
  description: 'Comprehensive API for managing properties, leases, tenants, and all aspects of real estate management.

    Built with Rust and Actix-web following hexagonal architecture principles.


    ## Authentication

    This API uses API keys for authentication with tenant-based isolation.


    ## Base URL

    - Production: `https://api.faireplace.com/api`'
  version: 1.0.0
  contact:
    name: FairePlace API Support
    email: api-support@faireplace.com
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
servers:
- url: https://api.faireplace.com/api
  description: Production server
security:
- BearerAuth: []
tags:
- name: Payments
  description: Checkout sessions, payment status, and payment confirmation.
paths:
  /credits/purchase:
    post:
      operationId: purchaseCredits
      summary: Purchase credits
      description: '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:


        ```json

        {

        "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


        ```bash

        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**:

        ```json

        {

        "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.'
      tags:
      - Payments
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PurchaseCreditsRequest'
            examples:
              purchase_starter_pack:
                summary: Purchase of the Starter Pack
                value:
                  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
      responses:
        '201':
          description: '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.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PurchaseCreditsResponse'
              examples:
                success:
                  summary: Session created successfully
                  value:
                    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
        '400':
          description: 'Invalid request.


            **Possible causes**:

            - Invalid `package_id` (not a valid UUID)

            - Invalid `success_url` or `cancel_url` (not valid URLs)

            - User does not have a Stripe account (`stripeCustomerId` missing in Better Auth)

            - Package does not have a `stripe_price_id` configured

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                invalid_package_id:
                  summary: Invalid package ID
                  value:
                    error:
                      code: VALIDATION_ERROR
                      message: 'Invalid package_id: invalid uuid'
                      status: 400
                no_stripe_account:
                  summary: No Stripe account
                  value:
                    error:
                      code: BUSINESS_ERROR
                      message: You must have a Stripe account to purchase credits
                      status: 400
                no_stripe_price_id:
                  summary: Package without Stripe Price ID
                  value:
                    error:
                      code: VALIDATION_ERROR
                      message: Package has no Stripe price ID
                      status: 400
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: 'Access forbidden.


            The user does not have the **owner** role required to purchase credits.

            Only owners can have a Stripe account and purchase credits.

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: 'Package not found or inactive.


            The provided `package_id` does not exist, does not belong to the tenant,

            or is inactive (and `active_only=true` by default).

            '
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  schemas:
    PurchaseCreditsRequest:
      type: object
      description: 'Request to initiate a credit purchase.


        This request creates a Stripe Checkout Session and returns the payment URL.

        Payment is processed by Stripe, and credits are automatically credited

        via webhook when payment is confirmed.

        '
      required:
      - package_id
      - success_url
      - cancel_url
      properties:
        package_id:
          type: string
          format: uuid
          description: 'Identifier of the credit package to purchase.


            The package must be active and have a configured `stripe_price_id`.

            '
          example: 550e8400-e29b-41d4-a716-446655440000
        success_url:
          type: string
          format: uri
          description: '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}`

            '
          example: https://app.fairplace.com/credits/success?session_id={CHECKOUT_SESSION_ID}
        cancel_url:
          type: string
          format: uri
          description: '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: https://app.fairplace.com/credits/cancel
    Error:
      type: object
      description: "The error envelope returned by every authenticated endpoint.\n\nTwo things are worth knowing before you write your error handling:\n\n- **`code` is a symbolic string, not a number.** The numeric HTTP status is\n  in `status`. Branch on `code`: it is stable, and show `message`, which\n  is written for humans and may be reworded without notice.\n- The public guest-signature endpoints use a **different, flatter shape**\n  (`{ \"error_code\": …, \"message\": … }`, no `error` wrapper), because they\n  are consumed by a page that has no session. Their responses document it\n  inline.\n\nThe `X-Request-Id` response header carries the request identifier: quote it\nwhen reporting a problem. It is a header, not a body field.\n"
      required:
      - error
      properties:
        error:
          type: object
          required:
          - code
          - message
          - status
          properties:
            code:
              type: string
              description: Stable symbolic code. Branch on this.
              enum:
              - NOT_FOUND
              - UNAUTHORIZED
              - VALIDATION_ERROR
              - DATABASE_ERROR
              - BUSINESS_ERROR
              - STORAGE_ERROR
              - CONFIG_ERROR
              - FORBIDDEN
              - CONFLICT
              - PARSE_ERROR
              - SERIALIZATION_ERROR
              - AUTHENTICATION_ERROR
              - AUTHORIZATION_ERROR
              - EXTERNAL_SERVICE_ERROR
              - RATE_LIMIT_EXCEEDED
              - PAYMENT_REQUIRED
              - PLAN_LIMIT_REACHED
              - GONE
              - BAD_REQUEST
              - INTERNAL_ERROR
              - INTERNAL_SERVER_ERROR
              example: NOT_FOUND
            message:
              type: string
              description: 'Human-readable explanation, most often in French. Safe to display,

                not safe to parse.

                '
              example: Lease not found
            status:
              type: integer
              description: The HTTP status code, repeated in the body.
              example: 404
            details:
              type: object
              additionalProperties: true
              description: 'Extra machine-readable context. Only present on some errors: on

                `RATE_LIMIT_EXCEEDED` it carries `retry_after_seconds`.

                '
              example:
                retry_after_seconds: 12
    PurchaseCreditsResponse:
      type: object
      description: 'Response after creating a credit purchase session.


        Contains the Stripe Checkout page URL where the user must be redirected

        to complete the payment.

        '
      required:
      - checkout_url
      - package_id
      - package_name
      - credits_amount
      - price_cents
      properties:
        checkout_url:
          type: string
          format: uri
          description: '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.

            '
          example: https://checkout.stripe.com/c/pay/cs_test_a1b2c3d4e5f6...
        package_id:
          type: string
          format: uuid
          description: 'Identifier of the selected package.

            '
          example: 550e8400-e29b-41d4-a716-446655440000
        package_name:
          type: string
          description: 'Name of the selected package.

            '
          example: Pack Starter
        credits_amount:
          type: integer
          format: int64
          description: 'Number of credits that will be credited after successful payment (in cents).

            '
          example: 1000
        price_cents:
          type: integer
          format: int64
          description: 'Package price in euro cents.

            '
          example: 2990
  responses:
    InternalServerError:
      description: Internal Server Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: API key with fp_* prefix, passed as Bearer token
    WorkerApiKey:
      type: apiKey
      in: header
      name: X-API-Key
    WorkerBearer:
      type: http
      scheme: bearer
      bearerFormat: Worker