Reseller Payment Webhook
Transfer SMS units from parent company to child company after receiving payment. This endpoint is used in the RoyceTalk reseller program for parent-to-child balance transfers.
For Reseller Parents Only
This endpoint is exclusively for parent companies in the reseller hierarchy. When a child company pays you via M-Pesa or another payment method, you call this endpoint to transfer SMS units from your balance to theirs.
Not a reseller parent? This endpoint won't work for you. Contact support to set up a reseller account.
ENDPOINT
POST /api/v1/sms-api/webhooks/payment/AUTHENTICATION
Bearer Token (Parent API Key)How It Works
Child Pays Parent
Your child company sends payment to your M-Pesa paybill or bank account (e.g., KES 1,100 to buy 2,000 SMS units at KES 0.55 per unit).
You Receive Payment Callback
M-Pesa (or your payment provider) sends a callback to your payment system with transaction details: amount, reference, account name.
Call This Webhook
Your payment system calls this endpoint with your parent API key, child's account name, payment amount, and M-Pesa reference.
SMS Units Transferred
RoyceTalk transfers SMS units from your balance to your child's balance. You get a detailed response with profit calculation and new balances.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
account_name | string | Yes | Child company's account name (max 255 characters) |
amount | decimal | Yes | Payment amount received (e.g., "1100.00"). Must be greater than 0. |
payment_reference | string | Recommended | Unique payment reference (e.g., M-Pesa transaction ID). Used for duplicate prevention. Max 100 characters, alphanumeric plus dash/underscore only. |
currency | string | Optional | Payment currency (ISO 4217 code). Defaults to parent company's currency. Must match parent's currency if provided. |
Important: Always Provide payment_reference
While technically optional, we highly recommend always providing a uniquepayment_reference (e.g., M-Pesa transaction ID). This prevents duplicate processing if your system accidentally calls this endpoint twice with the same payment.
Code Examples
Replace YOUR_PARENT_API_KEY_HERE with your actual parent company API key.
import requests
from datetime import datetime
# Your parent company API credentials
PARENT_API_KEY = "YOUR_PARENT_API_KEY_HERE"
API_URL = "https://roycetalk.com/api/v1/sms-api/webhooks/payment/"
def process_child_payment(child_account_name, amount, mpesa_reference):
"""
Process payment from child company and transfer SMS units.
Args:
child_account_name: Child company's account name
amount: Payment amount received from child
mpesa_reference: M-Pesa transaction reference
Returns:
dict: Transfer result with balance updates
"""
# Prepare the request
headers = {
"Authorization": f"Bearer {PARENT_API_KEY}",
"Content-Type": "application/json"
}
payload = {
"account_name": child_account_name,
"amount": str(amount),
"payment_reference": mpesa_reference,
"currency": "KES"
}
try:
# Send the request
response = requests.post(API_URL, json=payload, headers=headers)
# Check response status
if response.status_code == 200:
result = response.json()
print("✓ Payment processed successfully!")
print(f"Transfer Reference: {result['data']['transfer_reference']}")
print(f"SMS Units Transferred: {result['data']['transfer_details']['sms_units_transferred']}")
print(f"Parent Balance After: {result['data']['parent_company']['balance_after']}")
print(f"Child Balance After: {result['data']['child_company']['balance_after']}")
print(f"Parent Profit: KES {result['data']['parent_company']['profit']}")
return result
elif response.status_code == 409:
# Duplicate payment reference
error = response.json()
print(f"⚠ Duplicate payment: {error['errors'][0]['message']}")
print(f"Original transaction: {error['errors'][0]['details']['existing_transfer']}")
return None
elif response.status_code == 404:
# Child company not found
error = response.json()
print(f"✗ Child company not found: {error['errors'][0]['message']}")
return None
elif response.status_code == 400:
# Validation error or insufficient balance
error = response.json()
print(f"✗ Error: {error['errors'][0]['message']}")
if 'details' in error['errors'][0]:
print(f"Details: {error['errors'][0]['details']}")
return None
else:
print(f"✗ Unexpected error: {response.status_code}")
print(response.text)
return None
except requests.exceptions.RequestException as e:
print(f"✗ Request failed: {str(e)}")
return None
# Example usage
if __name__ == "__main__":
# Process a payment from child company
result = process_child_payment(
child_account_name="child_company_abc",
amount=1100.00,
mpesa_reference="MPESA_ABC123XYZ"
)
if result:
# Payment processed successfully
# You can store the transfer_reference in your database
transfer_ref = result['data']['transfer_reference']
print(f"\n✓ Store this transfer reference: {transfer_ref}")Success Response
Understanding the Response
- profit: Your revenue (what child paid) minus your cost (units × your rate). This is your profit from the transaction.
- calculation: Shows how SMS units were calculated: amount ÷ child's buying rate.
- balance_before/after: Both parent and child balances before and after the transfer.
- transfer_reference: Unique reference for this transfer. Store this in your database for reconciliation.
Error Responses
This payment reference has already been used. The response includes details of the original transaction. This is normal if you retry a failed request - the original transfer succeeded, so no double-charging occurs.
The child company either doesn't exist, is inactive, or doesn't belong to you. Verify the account_name is correct.
You don't have enough SMS units to fulfill this transfer. Top up your parent account balance and retry.
One or more request parameters are invalid. Check the details field for specific validation errors.
Best Practices
Always Use Unique Payment References
Use M-Pesa transaction IDs or other unique identifiers as the payment_reference. This prevents accidental double-processing and provides a clear audit trail.
Store Transfer References
Save the transfer_reference from successful responses in your database. This helps with reconciliation and troubleshooting.
Handle 409 Gracefully
A 409 Conflict response means the payment was already processed successfully. Don't treat this as an error - use the returned existing_transfer details to confirm the original transfer.
Log Profit for Accounting
The response includes your profit from each transaction. Log this for financial reporting and reconciliation.
Don't Retry Failed Payments Without Investigation
If you get a 400 or 500 error, investigate the cause before retrying. Check logs, verify balances, and confirm the child account name is correct.
Monitor Your Parent Balance
Set up alerts when your parent balance drops below a threshold. This prevents "insufficient balance" errors when processing child payments.
Common Integration Scenarios
Scenario 1: M-Pesa Paybill Integration
Most common scenario: Child companies pay you via your M-Pesa paybill.
1. Child sends money to your M-Pesa paybill
2. M-Pesa sends callback to your server with transaction details
3. Extract: amount, M-Pesa reference, account number (child's account name)
4. Call this webhook with extracted data
5. SMS units automatically transferred to child
Scenario 2: Manual Bank Transfer
Child companies pay via bank transfer or other manual payment methods.
1. Child sends bank transfer with their account name in reference
2. You receive bank notification (email/SMS/statement)
3. Manually call this webhook via your admin panel or script
4. Provide: child account name, amount, bank reference
5. SMS units transferred to child