Skip to content

Payment Integration

This guide explains the complete payment flow for accepting testimony offers using Stripe integration.

Overview

The payment process involves three main steps:

  1. Checkout Initiation - Client initiates payment and receives a Stripe checkout URL
  2. Payment Processing - Client completes payment on Stripe's secure checkout page
  3. Payment Confirmation - Application confirms payment and accepts the offer

Prerequisites

Before You Start

Ensure these requirements are met before initiating payment:

Step-by-Step Flow

Step 1: Initiate Checkout

Endpoint: Checkout Offer

http
POST /api/v1/testimonies/offers/{offer}/checkout

Required Data:

  • phone - Unique phone number (different from authenticated user)
  • firstName - Client's first name
  • lastName - Client's last name
  • billingAddress - Billing address object
  • shippingAddress - Shipping address (optional, uses billing if omitted)
  • company - Company details (optional, for business purchases)

Request Example:

json
{
  "phone": "+421902123456",
  "firstName": "Peter",
  "lastName": "Novák",
  "billingAddress": {
    "line1": "Hlavná 123",
    "line2": "Apartment 4B",
    "city": "Bratislava",
    "postalCode": "811 01",
    "country": "SK"
  },
  "shippingAddress": {
    "line1": "Trieda SNP 1",
    "line2": "",
    "city": "Košice",
    "postalCode": "040 01",
    "country": "SK"
  },
  "company": {
    "businessId": "12345678",
    "taxId": "2023456789",
    "vatId": "SK2023456789"
  }
}

Response:

json
{
  "data": {
    "url": "https://checkout.stripe.com/c/pay/cs_test_a1..."
  }
}

Step 2: Complete Payment on Stripe

  1. Redirect User - Redirect the client to the url returned in Step 1
  2. Stripe Checkout - Client completes payment on Stripe's secure page
  3. Stripe Redirect - After successful payment, Stripe redirects back to your application with a sessionId parameter

Example Redirect URLs:

Success: https://your-app.com/payment/success?sessionId=cs_test_a1...
Cancel:  https://your-app.com/payment/cancel?sessionId=cs_test_a1...

Step 3: Confirm Payment

Endpoint: Accept Offer

http
POST /api/v1/testimonies/offers/accept

Required Data:

  • sessionId - The session ID returned from Stripe redirect

Request Example:

json
{
  "sessionId": "cs_test_a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6q7R8s9T0"
}

Response:

204 No Content

Step 4: Verify Acceptance

After successful payment confirmation, the testimony transitions to accepted state.

Verify State: Show Testimony

http
GET /api/v1/testimonies/{testimonyId}

Check for:

  • state should be "accepted"
  • acceptedOffer should contain the offer details
  • expert should be populated

State Transitions

The payment flow triggers the following state transitions:

pending → offered → accepted

See Testimony Workflow for complete state transition diagram.

Commission Calculation

The total payment amount includes:

  • Offer Price - Amount set by the expert
  • Commission - Platform fee (default 21%)

Example:

Expert Offer:  €500
Commission:    €105 (21% of €500)
Total Payment: €605

The commission is calculated automatically and included in the Stripe checkout session. See Offer Object for commission details.

Error Handling

Checkout Errors

If checkout initiation fails:

422 Unprocessable Content

json
{
  "message": "The phone has already been taken.",
  "errors": {
    "phone": [
      "The phone has already been taken."
    ]
  }
}

Common Issues:

  • Phone number already registered
  • Phone number matches authenticated user
  • Invalid address data
  • Invalid country code

500 Internal Server Error

json
{
  "message": "An unexpected error occurred."
}

Payment Confirmation Errors

If payment confirmation fails:

422 Unprocessable Content

json
{
  "message": "Invalid session ID or payment not completed.",
  "errors": {
    "sessionId": [
      "Invalid session ID or payment not completed."
    ]
  }
}

Common Issues:

  • Invalid or expired session ID
  • Payment not completed on Stripe
  • Session already used
  • Offer no longer available

Security Notes

Security Best Practices

  • All payment processing is handled by Stripe's PCI-compliant infrastructure
  • No credit card data is stored in the application
  • Session IDs are single-use and expire after confirmation
  • Phone number uniqueness prevents duplicate accounts

Testing

Testing Payments

For testing the payment flow:

  1. Use Stripe test mode credentials
  2. Use test card numbers from Stripe Testing Docs
  3. Common test cards:
    • Success: 4242 4242 4242 4242
    • Decline: 4000 0000 0000 0002

See Email Testing for viewing payment notification emails.

Integration Example

Frontend Flow (Pseudocode)

javascript
// Step 1: Initiate checkout
async function initiateCheckout(offerId, checkoutData) {
  const response = await fetch(`/api/v1/testimonies/offers/${offerId}/checkout`, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(checkoutData)
  });

  const { data } = await response.json();

  // Step 2: Redirect to Stripe
  window.location.href = data.url;
}

// Step 3: Handle Stripe redirect (on your success page)
async function handlePaymentSuccess() {
  const urlParams = new URLSearchParams(window.location.search);
  const sessionId = urlParams.get('sessionId');

  if (!sessionId) {
    throw new Error('No session ID found');
  }

  // Confirm payment
  await fetch('/api/v1/testimonies/offers/accept', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ sessionId })
  });

  // Redirect to testimony details
  window.location.href = `/testimonies/${testimonyId}`;
}