Payments
This guide covers the complete payment flow in ToffeePay, from creating payment sessions to handling confirmations.
Payment Flow
Create a Payment Session
Send a server-side request to create a payment session.
POST /pay.v1.PaymentService/CreateSession
Authorization: Bearer <your_api_key>
Content-Type: application/json
{
"game_id": "space_shooter",
"user_id": "player_42",
"item": {
"title": "50 Gold Coins",
"price": 499,
"currency": "USD",
"image": "data:image/png;base64,..."
},
"return_url": "mygame://payment-complete"
}
Parameters:
game_id
: Your unique game identifieruser_id
: Unique identifier for the playeritem
: The item being purchasedtitle
: Display name of the itemprice
: Price in cents (e.g., 499 = $4.99)currency
: Three-letter currency code (USD, EUR, etc.)image
: Base64-encoded image or URL
return_url
: Deep link to return to after payment
Response
{
"id": "sess_abc123",
"url": "https://pay.toffeepay.com/sess_abc123"
}
Payment Statuses
Session Statuses
Payment sessions can have the following statuses:
pending
: Payment session created but not yet paidpaid
: Payment successfully completedfailed
: Payment attempt failedcancelled
: Payment session was cancelledexpired
: Payment session has expired
Payment Statuses
Individual payment objects (created when processing a session) have these statuses:
processing
: Payment is being processed by the payment providerauthorized
: Payment has been authorized but not yet capturedsucceeded
: Payment completed successfullycancelled
: Authorized payment was cancelled before capturefailed
: Payment processing failed
Status Flow:
-
Session starts as
pending
-
When payment begins, a Payment object is created with status
processing
-
Payment can transition to:
authorized
: Payment authorized but not capturedsucceeded
: Payment completed successfully (either automatically or via CompletePayment)cancelled
: Authorized payment was cancelled via CancelPaymentfailed
: Payment processing failed
Note: Whether payments automatically proceed from
authorized
tosucceeded
or require manual completion via CompletePayment is configured during game setup. -
Session status updates based on final payment status:
paid
(if payment succeeded)cancelled
(if session was cancelled manually via CancelSession or after 3 cancelled payment attempts)failed
(after 3 failed payment attempts)
Timestamp Fields
Both sessions and payments include relevant timestamp fields:
Session timestamps:
created_at
: When the session was createdpaid_at
: When the session was successfully paid (if applicable)failed_at
: When the session failed (if applicable)expired_at
: When the session expired (if applicable)cancelled_at
: When the session was cancelled (if applicable)
Payment timestamps:
created_at
: When payment processing beganauthorized_at
: When payment was authorized (if applicable)succeeded_at
: When payment completed successfully (if applicable)cancelled_at
: When payment was cancelled (if applicable)failed_at
: When payment failed (if applicable)
Webhook Events
ToffeePay sends webhooks for the following payment-related events:
Session Events
session.created
: When a payment session is createdsession.paid
: When a session is successfully paidsession.failed
: When payment attempt related to this session failssession.expired
: When a session expires without paymentsession.cancelled
: When session is cancelled by user
Payment Events
payment.created
: When a payment is created and processing beginspayment.authorized
: When payment is authorized but not yet capturedpayment.succeeded
: When payment completes successfullypayment.cancelled
: When an authorized payment is cancelledpayment.failed
: When payment attempt fails
See the Webhooks page for implementation details and signature verification.
Open the Payment Page
Open the returned payment_url
in the browser or webview.
The user will:
- View the item details and total price
- Pay using Apple Pay, Google Pay, or other supported methods
- Be redirected back to your game via the
return_url
Handle Payment Notifications
ToffeePay notifies you of payment events through two methods:
1. Webhooks
When a payment is completed, ToffeePay sends a signed webhook to your backend. See the Webhooks page for detailed implementation.
Sample Payload:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"event": "payment.succeeded",
"timestamp": "2023-06-01T12:05:00Z",
"data": {
"payment_id": "pay_xyz789"
}
}
2. Return URL
After payment, the user is redirected to your specified return_url
. This is typically a custom deep link that your game handles.
Example:
"return_url": "mygame://payment-complete"
Cancel a Payment Session
You can cancel a payment session that is still in pending
status:
POST /pay.v1.PaymentService/CancelSession
Authorization: Bearer <your_api_key>
Content-Type: application/json
{
"id": "sess_abc123"
}
Response:
{}
When a session is cancelled:
- The session status changes to
cancelled
- The
cancelled_at
timestamp is set - A
session.cancelled
webhook event is sent - The session cannot be paid and the payment URL becomes invalid
Check Session Status
To confirm session status (especially when handling return URLs), you can use either endpoint:
GetSession (Full Details)
POST /pay.v1.PaymentService/GetSession
Authorization: Bearer <your_api_key>
Content-Type: application/json
{
"id": "sess_abc123"
}
Response:
{
"id": "sess_abc123",
"status": "paid",
"payment_id": "pay_xyz789",
"user_id": "player_42",
"game_id": "space_shooter",
"item": {
"title": "50 Gold Coins",
"price": 499,
"currency": "USD"
},
"tax": {
"amount": 50
},
"created_at": "2023-06-01T12:00:00Z",
"paid_at": "2023-06-01T12:05:00Z"
}
GetSessionStatus (Status Only)
POST /pay.v1.PaymentService/GetSessionStatus
Authorization: Bearer <your_api_key>
Content-Type: application/json
{
"id": "sess_abc123"
}
Response:
{
"id": "sess_abc123",
"status": "paid"
}
Status handling:
- If
status
ispaid
, grant the items and show success - If
status
ispending
, show a waiting screen - If
status
isfailed
,cancelled
orexpired
, inform the user and offer to retry
Complete Payment
When your game wants to control when an authorized payment is captured, use CompletePayment. This is useful for scenarios where you want to authorize payment but only capture it after fulfilling the order (e.g., confirming item availability).
POST /pay.v1.PaymentService/CompletePayment
Authorization: Bearer <your_api_key>
Content-Type: application/json
{
"id": "pay_xyz789"
}
Parameters:
id
: The payment ID to complete
Response:
{}
Cancel Payment
Cancel an authorized payment before it's captured. This releases the hold on the customer's payment method.
POST /pay.v1.PaymentService/CancelPayment
Authorization: Bearer <your_api_key>
Content-Type: application/json
{
"id": "pay_xyz789"
}
Parameters:
id
: The payment ID to cancel
Response:
{}
Get Payment Details
Retrieve details of a payment:
POST /pay.v1.PaymentService/GetPayment
Authorization: Bearer <your_api_key>
Content-Type: application/json
{
"id": "pay_xyz789"
}
Response:
{
"id": "pay_xyz789",
"session_id": "sess_abc123",
"status": "succeeded",
"amount": 499,
"currency": "USD",
"method": "apple_pay",
"details": "50 Gold Coins",
"created_at": "2023-06-01T12:05:00Z",
"succeeded_at": "2023-06-01T12:05:30Z"
}
List Sessions
Retrieve historical sessions for audit and analytics:
POST /pay.v1.PaymentService/ListSessions
Authorization: Bearer <your_api_key>
Content-Type: application/json
{
"game_id": "space_shooter",
"user_id": "player_42",
"status": "paid",
"limit": 50,
"offset": 0
}
Response:
{
"sessions": [
{
"id": "sess_abc123",
"status": "paid",
"payment_id": "pay_xyz789",
"user_id": "player_42",
"game_id": "space_shooter",
"item": {
"title": "50 Gold Coins",
"price": 499,
"currency": "USD"
},
"tax": {
"amount": 50
},
"created_at": "2023-06-01T12:00:00Z",
"paid_at": "2023-06-01T12:05:00Z"
}
],
"total": 1,
"has_more": false
}
List Payments
Retrieve historical payments (successful transactions only):
POST /pay.v1.PaymentService/ListPayments
Authorization: Bearer <your_api_key>
Content-Type: application/json
{
"game_id": "space_shooter",
"user_id": "player_42",
"limit": 50,
"offset": 0
}
Response:
{
"payments": [
{
"id": "pay_xyz789",
"session_id": "sess_abc123",
"status": "succeeded",
"amount": 499,
"currency": "USD",
"method": "apple_pay",
"details": "50 Gold Coins",
"created_at": "2023-06-01T12:05:00Z",
"succeeded_at": "2023-06-01T12:05:30Z"
}
],
"total": 1,
"has_more": false
}
Tax Handling
ToffeePay automatically calculates and applies taxes based on the customer's location. Tax information is included in session responses when the session is completed.
Tax Structure
The tax object in session responses contains:
amount
: Tax amount in cents (same currency as the item price)
Example
For a $4.99 item with $0.50 tax:
{
"item": {
"price": 499,
"currency": "USD"
},
"tax": {
"amount": 50
}
}
The customer will be charged the total amount (item price + tax = $5.49 in this example).
Note: Tax calculations are handled automatically during payment processing. The tax amount is determined at the time of payment based on the customer's billing address.
Image Requirements
Item images must meet these requirements:
- Format: PNG, JPG, WebP
- Size: ≤ 300 KB recommended
- Encoding: Base64 with MIME prefix or direct URL
Base64 format:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
URL format:
https://yourgame.com/images/gold-coins.png
Best Practices
- Authentication: See Authentication for API key management
- Idempotency: Use Idempotency-Key header to prevent duplicate operations
- Webhook verification: Always verify webhook signatures (see Webhooks)
- Error handling: Implement proper error handling for all payment statuses
- User experience: Show loading states and clear success/failure messages
- Security: Use HTTPS for all webhook endpoints and return URLs
- Testing: Use sandbox mode for development and testing
Error Handling
Common payment errors and how to handle them:
invalid_game_id
: Check your game registration and API key (see Authentication)invalid_currency
: Ensure currency code is supported (USD, EUR, etc.)invalid_price
: Price must be a positive integer in centsinvalid_image
: Check image format and size requirementssession_expired
: Payment session has expired, create a new oneinsufficient_funds
: User's payment method was declined
Testing
Use ToffeePay's sandbox environment for testing:
- Use sandbox API keys (different from production)
- Test with various payment methods and failure scenarios
- Verify webhook delivery and signature verification
- Test return URL handling in your game client