m2pfintech
API LibraryCard Tokenization

Create Card Token (Frontend Only)

Tokenize a customer's card by submitting AES-encrypted card data directly from the customer's browser or mobile app. Returns an altId (M2P card token) that can be used in AFT pull and OCT push calls with tokenType: "01".

⚠️ This call MUST originate from the customer's frontend (browser/app), NOT from your backend server. If your backend relays this call, card data enters PCI scope on your systems, violating the non-PCI compliance boundary.

Use the url returned by POST /bitUrl/v2/generateSharedSecret as the full endpoint for this request (it contains a signed session key query parameter).

Encryption Flow (JavaScript example)

const { CryptoJS } = window; // load from cdnjs

// Keys derived from the generateSharedSecret response
const cvvAESKey   = CryptoJS.SHA256(serverPublicKey);
const payloadKey  = CryptoJS.SHA256(sharedSecret);
const iv = CryptoJS.enc.Hex.parse("00000000000000000000000000000000");

// 1. Encrypt CVV using serverPublicKey-derived key
const encryptedCvv = CryptoJS.AES.encrypt(
  cvv, cvvAESKey, { iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }
).toString();

// 2. Build payload and encrypt the whole thing using sharedSecret-derived key
const payload = {
  cardNumber: "4012001037141112",
  cardExpiry: "2027-12",
  cvv: encryptedCvv,          // CVV is double-encrypted
  networkType: "VISA",
  business: "YOUR_BUSINESS_CODE",
  entityId: "1234567890"
};
const encryptedReq = CryptoJS.AES.encrypt(
  JSON.stringify(payload), payloadKey, { iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }
).toString();

The encryptedReq string above is the value to submit in the request body.

Token Lifecycle

  • Token state: ACTIVECONSUMED (after one successful transaction) or EXPIRED (after ~15 min TTL)
  • Tokens are single-use — each AFT/OCT transaction consumes the token
POST
/visadirect/createCardToken

Authorization

BasicAuth
AuthorizationBasic <token>

Partner credentials (username/password) provisioned during onboarding

In: header

Query Parameters

key*string

Signed session key from the url returned by generateSharedSecret. This is automatically included when using the full url from that response.

Header Parameters

TENANT*string

Tenant identifier (sponsor bank)

Request Body

application/json

encryptedReq*string

AES-CBC encrypted payload (Base64 string). Contains the customer's card data encrypted using the sharedSecret-derived AES key from the generateSharedSecret response. The CVV within the payload is additionally encrypted using the serverPublicKey-derived AES key (double-encrypted).

Plaintext payload structure (before encryption):

{
  "cardNumber": "4012001037141112",
  "cardExpiry": "2027-12",
  "cvv": "<AES-encrypted CVV>",
  "networkType": "VISA",
  "business": "YOUR_BUSINESS_CODE",
  "entityId": "1234567890"
}

Response Body

application/json

application/json

application/json

application/json

curl -X POST "https://secure.yappay.in/Yappay/visadirect/createCardToken?key=eyJhbGciOiJIUzI1NiJ9..." \  -H "TENANT: TENANT_NAME" \  -H "Content-Type: application/json" \  -d '{    "encryptedReq": "U2FsdGVkX1+8Xn3mKp2oAa7z..."  }'

{
  "result": {
    "altId": "b879509e-c5c2-42fa-b844-a07516983b76",
    "tokenPanExpiry": "2026-04"
  },
  "exception": null,
  "pagination": null
}

{
  "result": null,
  "error": {
    "errorCode": "VALIDATION_ERROR",
    "shortMessage": "Invalid request",
    "detailMessage": "recipientPan is required",
    "fieldErrors": [
      "recipientPan: must not be blank"
    ]
  }
}
{
  "result": null,
  "error": {
    "errorCode": "AUTH_FAILED",
    "shortMessage": "Authentication failed",
    "detailMessage": "Invalid credentials"
  }
}
{
  "result": null,
  "error": {
    "errorCode": "INTERNAL_ERROR",
    "shortMessage": "Internal server error",
    "detailMessage": "An unexpected error occurred. Please contact support."
  }
}