Payment Intents
A payment intent is a high-level abstraction that represents the entire payment process. It serves as a container for all the necessary information required to initiate and manage a payment transaction.
What is a Payment Intent?
Think of a payment intent as a "payment session" or "payment request" that captures:
- Amount and Currency: How much to charge and in what currency
- Customer Information: Who is making the payment (
purchaser_id) - Transaction Reference: Your internal reference ID (
reference_id) - Payment Preferences: Whether to save credentials, allow MIT, etc.
- Current Status: Where the payment is in its lifecycle
When you create a payment intent, NjiaPay generates a secure checkout URL that you redirect your customer to. This URL remains valid until the payment is completed, canceled, or expired.
Intent vs Attempt
It's important to understand the relationship between intents and attempts:
- Payment Intent: The overall payment request (e.g., "Customer wants to pay $100")
- Payment Attempt: A specific try at processing that payment with a particular payment method (e.g., "Customer tried to pay with Visa card ending in 1234")
Key differences:
- One intent can have multiple sequential attempts
- If an attempt fails, the intent can be retried with a different payment method
- The intent's status reflects the outcome of its most recent attempt
See Payment Attempts for more details on this relationship.
When to Create a Payment Intent
Create a payment intent whenever you want to collect a payment from a customer:
One-Time Payments
{
"amount": 50000,
"currency": "ZAR",
"reference_id": "order_12345",
"purchaser_id": "customer_abc",
"return_url": "https://yoursite.com/callback",
"allow_remember_credentials": false
}
First Payment with Credential Storage (for future auto-payments)
{
"amount": 50000,
"currency": "ZAR",
"reference_id": "subscription_init",
"purchaser_id": "customer_abc",
"return_url": "https://yoursite.com/callback",
"allow_remember_credentials": true,
"request_unscheduled_mit": true
}
Payment with Splits
{
"amount": 50000,
"currency": "ZAR",
"reference_id": "marketplace_order_789",
"purchaser_id": "buyer_123",
"return_url": "https://yoursite.com/callback",
"allow_remember_credentials": false,
"split": {
"split_type": "AMOUNT",
"splits": [
{
"beneficiary_id": "550e8400-e29b-41d4-a716-446655440000",
"amount": 40000,
"description": "Seller payment"
},
{
"beneficiary_id": "main_merchant_id",
"amount": 10000,
"description": "Platform fee"
}
]
}
}
Intent Properties
Core Properties
| Property | Type | Description |
|---|---|---|
id | UUID | Unique identifier for the intent |
status | string | Current status (selection, pending, success, failed, canceled, chargeback) |
amount | integer | Amount in minor units (cents) |
currency | string | ISO 4217 currency code |
reference_id | string | Your unique transaction reference |
purchaser_id | string | Your unique customer identifier |
created | datetime | When the intent was created |
Configuration Properties
| Property | Type | Description |
|---|---|---|
is_interactive | boolean | Whether customer interaction is required |
allow_remember_credentials | boolean | Whether credentials can be saved |
request_unscheduled_mit | boolean | Request permission for auto-payments |
require_unscheduled_mit | boolean | Require MIT capability |
capture_mode | string | immediate or prefer_delay |
payment_method_filter | object | Filter available payment methods |
Runtime Properties
| Property | Type | Description |
|---|---|---|
attempt_count | integer | Number of attempts made |
last_method | string | Last payment method used |
last_brand | string | Last payment brand used |
return_url | string | Where to redirect customer after payment |
Interactive vs Non-Interactive Intents
Interactive Intents (Default)
{
"is_interactive": true,
...
}
- Customer selects payment method via hosted checkout
- Requires
redirect_urlto send customer to checkout page - Used for: First-time payments, customer-initiated payments
Non-Interactive Intents
{
"is_interactive": false,
...
}
- No customer interaction required
- Used for auto-payments/MIT with stored credentials
- Created via
/api/intents/auto-attemptendpoint - See Auto Payments Guide
Intent Lifecycle
A payment intent progresses through various states based on payment attempts:
See Status Lifecycle for detailed status explanations.
Best Practices
✅ DO
- Use descriptive
reference_idvalues for easy tracking - Set
allow_remember_credentials: trueonly when needed - Handle all possible intent statuses in your webhook handler
- Store the
intent_idin your database for reconciliation - Use
purchaser_infoto pre-fill customer details
❌ DON'T
- Create multiple intents for the same transaction
- Rely solely on
return_urlfor payment confirmation - Reuse
reference_idvalues across different transactions - Expose the
redirect_urlor intent token to unauthorized users - Poll the API excessively, use webhooks instead
Security Considerations
Intent Tokens
When you create an intent, you receive a token (intent authentication token):
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"redirect_url": "https://app.infinic.com/checkout?intent=...&token=..."
}
This token (iauth parameter):
- Allows customers to view their own payment intent
- Cannot be used to access other intents
- Is included automatically in the
redirect_url - Should be treated as sensitive (but less sensitive than API keys)
PCI Compliance
By using payment intents with hosted checkout:
- You never handle raw card data
- NjiaPay manages PCI compliance
- Sensitive data is encrypted at rest
- Payment methods are tokenized