Integration Guide
End-to-end integration flow, feature toggle configuration, polling strategy, and error handling for Click to Pay.
End-to-End Integration Flow
Register the customer on M2P
Use the standard registration APIs to create the customer and assign a kit:
POST /Yappay/registration-manager/v4/registerIf CTP is enabled with ALL scope for your tenant, CTP enrollment is triggered automatically after successful registration — you can skip to step 4.
Assign a kit (if not done during registration)
If the card was not assigned during registration, use:
POST /Yappay/business-entity-manager/addCardCollect cardholder consent and enroll
Obtain explicit consent from the cardholder, then call:
POST /Yappay/click-to-pay/v1/registerEntityAndKitwith the entityId, kitNo, and consent object.
Poll for enrollment status
Use the returned requestTraceId to track the async operation:
POST /Yappay/click-to-pay/v1/fetchRequestStatusVerify enrollment
Once status is SUCCESS, confirm via:
POST /Yappay/click-to-pay/v1/fetchEntityDetailsor check the ctpStatus field in existing APIs:
GET /Yappay/business-entity-manager/fetchEntityByEntityid/{entityId}Feature Toggle Configuration
CTP is controlled via the BUSINESSCUSTOMFIELD table with the key click.to.pay.enable.
Toggle Formats
| Value | Behavior |
|---|---|
Y|ALL | CTP enabled for all entities. Auto-enrollment triggers on v3/v4 registration |
Y|entityId1|entityId2|... | CTP enabled only for listed entity IDs |
N | CTP disabled for the tenant |
Configuration Properties
All CTP configuration is stored in BUSINESSCUSTOMFIELD for each tenant:
| Property Key | Description | Example |
|---|---|---|
click.to.pay.enable | Feature toggle | Y|ALL |
default.country.code.clicktopay | Default country for ISO code conversion | India |
ctp.consent.version | Consent version sent to Visa | 1.0 |
ctp.default.locale | Default locale tag | en-US |
ctp.base.saas.url | Base URL of the CTP SaaS API | https://ctp-saas.internal/api |
ctp.callback.url | Webhook callback URL for SaaS | https://api.m2p.com/Yappay/click-to-pay/v1/clickToPayResponse |
ctp.default.state | Default state code | DL |
These configuration values are managed by M2P operations. Contact your account manager to configure CTP for your tenant.
Auto-Enrollment on Registration
When CTP is enabled with ALL scope (Y|ALL), the platform automatically triggers CTP enrollment after a successful customer registration via v3/register or v4/register.
This means for Y|ALL tenants, clients do not need to explicitly call the CTP registration API — enrollment happens automatically as part of the registration flow.
Auto-Sync on Profile Updates
When a customer's profile is updated via POST /business-entity-manager/updateentity, the platform automatically syncs relevant changes to the Visa CTP network:
| Updated Field(s) | CTP Action |
|---|---|
| First name, last name, email, contact number | CTP_UPDATE_ENTITY — syncs customer data to Visa |
| Address fields (address1, city, state, country, pincode) | CTP_UPDATE_KIT — syncs payment instrument data to Visa |
These syncs happen after the database transaction commits (using Spring @TransactionalEventListener with AFTER_COMMIT phase) and are non-blocking.
Polling Strategy
For operations where webhook delivery is not configured or as a fallback, use fetchRequestStatus polling:
Recommended Approach
Initial poll: After 5 seconds
Retry interval: Every 10 seconds
Max attempts: 12 (total ~2 minutes)
Fallback: If still IN_PROGRESS after 2 minutes, retry after 5 minutesInternal Retry Behavior
The fetchRequestStatus endpoint internally queries the SaaS /status endpoint with a built-in retry mechanism:
- 4 retry attempts with 1-second delay between each
- If the SaaS reports a completed status that hasn't been processed via webhook, the platform automatically processes it (updates CTP records and sends notifications)
The webhook is the primary status delivery mechanism. Polling via fetchRequestStatus should be used as a fallback or for manual status checks.
Error Handling
Common Error Scenarios
| Scenario | Error Code | Resolution |
|---|---|---|
| Entity not registered on M2P | Y109 / customer.id.invalid | Register the customer via v3/v4 registration API first |
| Kit not assigned to entity | Y2271 / kit.not.assigned | Assign the kit via addCard API |
| CTP not enabled for tenant | Y4038 / click.to.pay.error | Contact M2P operations to enable CTP |
| Entity not registered on CTP (for addKit) | Y4038 | Use registerEntityAndKit first to enroll the entity |
| Entity not ACTIVE on CTP (for remove) | Y4038 | Entity must be in ACTIVE state to remove |
| Kit not ACTIVE on CTP (for removeKit) | Y4038 | Kit must be in ACTIVE state to remove |
| Request Trace ID not found | 500 | Verify the requestTraceId was returned by a CTP API |
| SaaS API failure | Y4038 | CTP SaaS service may be temporarily unavailable — retry |
Error Response Format
All CTP errors follow the standard M2P response envelope:
{
"result": null,
"exception": {
"detailMessage": "Human-readable error description",
"cause": null,
"shortMessage": "Short error summary",
"languageCode": "en",
"errorCode": "Y4038",
"code": "click.to.pay.error",
"networkHttpStatusCode": null
},
"pagination": null
}Webhook Failure Handling
If a webhook callback indicates failure:
RequestTraceIDstatus is updated toFAILED- CTP entity/kit statuses remain unchanged (stay in
REGISTRATION_IN_PROGRESSorREMOVAL_IN_PROGRESS) - A failure notification is sent to the Message Queue queue with error details
- The operation can be retried by calling the original API again
Testing Checklist
Use this checklist to validate your CTP integration in the SIT environment:
- Customer registration creates entity successfully
- Kit is assigned to the entity
-
registerEntityAndKitreturnsrequestTraceIdand event type -
fetchRequestStatusshowsIN_PROGRESS→SUCCESSprogression -
fetchEntityDetailsreturns customer and payment instrument info withACTIVEstatus -
addKitenrolls additional cards successfully -
removeKitremoves a specific card (status →REMOVED) -
removeEntityremoves customer and all cards -
fetchEntityByEntityidshowsctpStatusfield at entity and kit levels -
getDetailsByKitNoshowsctpStatusandctpPaymentInstrumentIdfields - Customer profile update triggers automatic CTP sync
- Error scenarios return appropriate error codes
Frequently Asked Questions
Q: Can I enroll a customer in CTP without their explicit consent?
No. Visa requires documented cardholder consent before CTP enrollment. The consent object is mandatory in the registerEntityAndKit request.
Q: What happens if the SaaS webhook never arrives?
Use the fetchRequestStatus API to poll for the result. The status endpoint has built-in retry logic and will process the result if available from the SaaS layer.
Q: Can a customer be re-enrolled after removal?
Yes. After an entity is removed (REMOVED status), you can call registerEntityAndKit again to re-enroll them.
Q: Does card replacement affect CTP enrollment?
Yes. When a card is replaced via replaceCard, the new kit needs to be separately enrolled in CTP via addKit. The old kit's CTP enrollment is not automatically transferred.
Q: Is CTP enrollment preserved when a card is blocked?
Card blocking via block may trigger a CTP status update depending on the block type. Check the ctpStatus after blocking to confirm the current state.
