Auto Payments (MIT)
Auto payments allow you to initiate payments on behalf of your customers without requiring any action from them. This functionality is particularly useful for collecting recurring payments (subscriptions), automatic top-ups, or other automated billing processes where customer interaction is not needed.
What are MIT Payments?
MIT (Merchant-Initiated Transactions) are payments that you initiate without direct customer involvement, using previously stored payment credentials.
Common use cases:
- Monthly subscriptions
- Automatic renewals
- Top-up when balance is low
- Installment payments
- Usage-based billing
Prerequisites
Before you can make auto payments, the following conditions must be met:
1. Prior Successful Payment
The customer must have completed a previous successful payment where:
allow_remember_credentialswas set totrue- Either
request_unscheduled_mitorrequire_unscheduled_mitwas set totrue
2. Valid Stored Credential
You must have a valid credential token that:
- Was generated from a previous successful payment
- Uses a payment method that supports MIT
- Is still active (not expired or deleted)
How It Works
Step 1: Initial Payment with Credential Storage
Create the first payment intent with MIT enabled:
const response = await fetch("https://app.infinic.com/api/intents", {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
amount: 10000,
currency: "ZAR",
reference_id: "subscription_init_" + customerId,
purchaser_id: customerId,
return_url: "https://yoursite.com/callback",
allow_remember_credentials: true, // ← Enable credential storage
request_unscheduled_mit: true, // ← Request MIT permission
}),
});
Step 2: Obtain Credential Token
After the customer completes payment, you'll receive a PaymentCredential webhook event:
{
"type": "PaymentCredential",
"created": "2024-09-01T00:00:00Z",
"content": {
"intent_id": "550e8400-e29b-41d4-a716-446655440000",
"reference_id": "subscription_init_customer_123",
"purchaser_id": "customer_123",
"credential_token": "cred_token_abc123xyz",
"display_name": "Visa ****1234",
"is_mit_compatible": true,
"method": "card",
"brand": "visa",
"card_last4": "1234",
"card_expiry": "2025-12"
}
}
Store the credential_token securely in your database:
// Example: Store credential
await db.savePaymentCredential({
customer_id: event.content.purchaser_id,
credential_token: event.content.credential_token,
display_name: event.content.display_name,
card_last4: event.content.card_last4,
expiry: event.content.card_expiry,
});
Step 3: Create Auto-Payment Attempts
When it's time to charge the customer (e.g., monthly renewal), create an auto-payment attempt:
// Retrieve stored credential
const credential = await db.getPaymentCredential(customerId);
// Create auto-payment attempt
const response = await fetch(
"https://app.infinic.com/api/intents/auto-attempt",
{
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
amount: 10000,
currency: "ZAR",
reference_id: "subscription_month_2_" + customerId,
purchaser_id: customerId,
credentials: [credential.credential_token], // ← Use stored token
}),
},
);
const result = await response.json();
console.log("Payment status:", result.intent_status);
Step 4: Handle Auto-Payment Results
Auto-payments complete immediately (success or failure). Monitor via webhooks:
app.post("/webhook", async (req, res) => {
const event = req.body;
if (event.type === "StatusChange") {
const { status, reference_id, purchaser_id } = event.content;
if (status === "success") {
// Payment successful
await extendSubscription(purchaser_id);
await sendReceiptEmail(purchaser_id, reference_id);
} else if (status === "failed") {
// Payment failed
await handleFailedPayment(purchaser_id, event.content.failure_reason);
await notifyCustomerPaymentFailed(purchaser_id);
}
}
res.status(200).send("OK");
});
Monitoring Payment Status
You can also check payment status via API:
const response = await fetch(
`https://app.infinic.com/api/intents/${intent_id}?iauth=${intent_token}`,
{
headers: { Authorization: `Bearer ${API_KEY}` },
},
);
const intent = await response.json();
console.log("Status:", intent.status);
Handling Failed Auto-Payments
When an auto-payment fails:
- Check failure reason from webhook
- Notify customer about the failure
- Retry logic (if appropriate):
- Card expired → Request new card
- Insufficient funds → Retry in a few days
- Card declined → Request alternative payment method
Example retry logic:
async function handleFailedAutoPayment(customerId, failureReason) {
if (failureReason === "CardExpired") {
// Card expired - request customer update card
await sendCardUpdateRequest(customerId);
} else if (failureReason === "InsufficientFunds") {
// Retry in 3 days
await scheduleRetry(customerId, 3);
} else {
// Other failure - request new payment method
await requestNewPaymentMethod(customerId);
}
}
Error Scenarios
404: Credential Not Found
{
"detail": "Credential not found"
}
Cause: The credential token doesn't exist or was deleted
Solution: Request customer to add a new payment method
403: Not Authorized
{
"detail": "Not authorized to use this credential"
}
Cause: Credential belongs to a different merchant
Solution: Verify you're using the correct API key and credential
422: Not MIT Compatible
{
"detail": "Credential cannot be used for MIT transactions"
}
Cause: The payment method doesn't support MIT
Solution: Request customer to use a different payment method
Best Practices
✅ DO
- Store credential tokens securely (encrypted)
- Notify customers before charging them
- Handle failures gracefully with retry logic
- Keep customer payment methods up to date
- Send receipts after successful charges
- Allow customers to update/remove payment methods
- Set up monitoring for failed auto-payments
❌ DON'T
- Charge customers without prior agreement
- Ignore failed payment notifications
- Store full card details (use tokens only)
- Retry failed payments excessively
- Forget to handle expired cards
- Use credentials from interactive payments without MIT enabled