Payment Integration
This guide explains the complete payment flow for accepting testimony offers using Stripe integration.
Overview
The payment process involves three main steps:
- Checkout Initiation - Client initiates payment and receives a Stripe checkout URL
- Payment Processing - Client completes payment on Stripe's secure checkout page
- Payment Confirmation - Application confirms payment and accepts the offer
Prerequisites
Before You Start
Ensure these requirements are met before initiating payment:
- Client is authenticated
- Testimony exists in
offeredstate (see Testimony Workflow) - Expert has created an offer (see Create Offer)
- Offer includes price and commission amount (see Offer Object)
Step-by-Step Flow
Step 1: Initiate Checkout
Endpoint: Checkout Offer
POST /api/v1/testimonies/offers/{offer}/checkoutRequired Data:
phone- Unique phone number (different from authenticated user)firstName- Client's first namelastName- Client's last namebillingAddress- Billing address objectshippingAddress- Shipping address (optional, uses billing if omitted)company- Company details (optional, for business purchases)
Request Example:
{
"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:
{
"data": {
"url": "https://checkout.stripe.com/c/pay/cs_test_a1..."
}
}Step 2: Complete Payment on Stripe
- Redirect User - Redirect the client to the
urlreturned in Step 1 - Stripe Checkout - Client completes payment on Stripe's secure page
- Stripe Redirect - After successful payment, Stripe redirects back to your application with a
sessionIdparameter
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
POST /api/v1/testimonies/offers/acceptRequired Data:
sessionId- The session ID returned from Stripe redirect
Request Example:
{
"sessionId": "cs_test_a1B2c3D4e5F6g7H8i9J0k1L2m3N4o5P6q7R8s9T0"
}Response:
204 No ContentStep 4: Verify Acceptance
After successful payment confirmation, the testimony transitions to accepted state.
Verify State: Show Testimony
GET /api/v1/testimonies/{testimonyId}Check for:
stateshould be"accepted"acceptedOffershould contain the offer detailsexpertshould be populated
State Transitions
The payment flow triggers the following state transitions:
pending → offered → acceptedSee 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: €605The 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
{
"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
{
"message": "An unexpected error occurred."
}Payment Confirmation Errors
If payment confirmation fails:
422 Unprocessable Content
{
"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:
- Use Stripe test mode credentials
- Use test card numbers from Stripe Testing Docs
- Common test cards:
- Success:
4242 4242 4242 4242 - Decline:
4000 0000 0000 0002
- Success:
See Email Testing for viewing payment notification emails.
Integration Example
Frontend Flow (Pseudocode)
// 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}`;
}