Subscription using Maya Card Payment Vault

Learn how to save a credit card for future payments or subscriptions

📘

What is Maya Card Payment Vault?

Maya Card Payment Vault allows your application to securely accept credit card information through tokenization for current and future transactions.

Why use Maya Card Payment Vault for card subscriptions?

By subscribing with Maya Card Payment Vault, you will be able to save your customer's credit card for future payments or subscriptions. Just follow these 5 steps:

Step 1 Setup Maya Business Manager

First, set up your Maya Business Manager account.

Step 2 Create a form that will accept credit card details

Maya Card Payment Vault will tokenize the card details without needing you to save it on your database.

️️️Is your platform PCI-DSS certified?

Do not store any card information (i.e. name, card number, expiry dates, cvv/cvc) on your application unless your platform is PCI-DSS certified.

<html>
  <head>
    <title>Save card</title>
  </head>
  <body>
    <form action="/tokenize-customer-card" method="POST">
      <input class="cn" placeholder="Card number">
      <input class="date" placeholder="MM / YY">
      <input class="cvc" placeholder="CVC" type="password">
      <button type="submit">Link a card</button>
    </form>
  </body>
</html>

Tokenizing the card details

Once the customer has submitted their card information, your server-side application should send this data to Create Payment Token to obtain a paymentTokenId to be used for the rest of process.

const express = require('express');
const app = express();
const fetch = require('node-fetch');

async app.post('/tokenize-customer-card', async (req, res) => {
	const createPaymentTokenUrl = 'https://pg-sandbox.paymaya.com/payments/v1/payment-tokens';
	const options = {
  	headers: {
    	'Content-Type': 'application/json',
    	'Authorization': `Basic ${btoa('SECRET_KEY')}`
  	},
		method: 'POST',
		body: req.body
	};

	const paymentTokenId = await fetch(url, options)
  	.then(res => res.json())
  	.then(json => {
   		return json.paymentTokenId
  	})
  	.catch(err => console.error('error:' + err));
});

app.listen(8080, () => console.log(`Listening on port ${8080}!`));

Step 3 Registering your customer to Maya Card Payment Vault

Your application should have the following fields below available for customer creation to Maya Card Payment Vault

{
  "id": "d29f1635-8313-4ed4-94e5-94b6a6018f52",
  "firstName": "Maya",
  "middleName": "Jose",
  "lastName": "Juan",
  "contact": {
    "phone": "+63(2)1234567890",
    "email": "[email protected]"
  },
  "billingAddress": {
    "line1": "6F Launchpad",
    "line2": "Sheridan Street",
    "city": "Mandaluyong City",
    "state": "Metro Manila",
    "zipCode": "1552",
    "countryCode": "PH"
  },
  "shippingAddress": {
    "firstName": "Maya",
    "middleName": "Jose",
    "lastName": "Juan",
    "line1": "6F Launchpad",
    "line2": "Sheridan Street",
    "city": "Mandaluyong City",
    "state": "Metro Manila",
    "zipCode": "1552",
    "countryCode": "PH",
    "phone": "+63(2)1234567890",
    "email": "[email protected]",
    "shippingType": "ST"
  },
  "sex": "F",
  "birthday": "1987-07-28",
  "customerSince": "2020-12-25",
  "createdAt": "2021-07-06T14:01:25.000Z",
  "updatedAt": "2021-07-06T14:01:25.000Z"
}

Your application's server will then send those user information to Vault using Create Customer endpoint.

const express = require('express');
const app = express();
const fetch = require('node-fetch');

async app.post('/tokenize-customer-card', async (req, res) => {
	const createPaymentTokenUrl = 'https://pg-sandbox.paymaya.com/payments/v1/payment-tokens';
	const options = {
  	headers: {
    	'Content-Type': 'application/json',
    	'Authorization': `Basic ${btoa('SECRET_KEY')}`
  	},
		method: 'POST',
		body: cardData
	};

	const paymentTokenId = await fetch(createPaymentTokenUrl, options)
  	.then(res => res.json())
  	.then(json => {
   		return json.paymentTokenId
  	})
  	.catch(err => console.error('error:' + err));
  
  
  const createCustomerUrl = 'https://pg-sandbox.paymaya.com/payments/v1/customers';
	const options = {
  	headers: {
    	'Content-Type': 'application/json',
    	'Authorization': `Basic ${btoa('SECRET_KEY')}`
  	},
		method: 'POST',
		body: customerData
	};

	const customerIdFromMayaVault = await fetch(createCustomerUrl, options)
  	.then(res => res.json())
  	.then(json => {
   		return json.id
  	})
  	.catch(err => console.error('error:' + err));
  
  
});

app.listen(8080, () => console.log(`Listening on port ${8080}!`));

Step 4 Link the customer to the card token

At this point, you will have 2 variables available customerId and paymentToken. Your server side application will need to link the 2 values to successfully vault using Create Card of Customer endpoint.

const express = require('express');
const app = express();
const fetch = require('node-fetch');

async app.post('/tokenize-customer-card', async (request, response) => {
	const createPaymentTokenUrl = 'https://pg-sandbox.paymaya.com/payments/v1/payment-tokens';
	const options = {
  	headers: {
    	'Content-Type': 'application/json',
    	'Authorization': `Basic ${btoa('SECRET_KEY')}`
  	},
		method: 'POST',
		body: cardData
	};

	const paymentTokenId = await fetch(createPaymentTokenUrl, options)
  	.then(res => res.json())
  	.then(json => {
   		return json.paymentTokenId
  	})
  	.catch(err => console.error('error:' + err));
  
  
  const createCustomerUrl = 'https://pg-sandbox.paymaya.com/payments/v1/customers';
	const options = {
  	headers: {
    	'Content-Type': 'application/json',
    	'Authorization': `Basic ${btoa('SECRET_KEY')}`
  	},
		method: 'POST',
		body: customerData
	};

	const customerIdFromMayaVault = await fetch(createCustomerUrl, options)
  	.then(res => res.json())
  	.then(json => {
      // Your code to keep the customerId on your application
   		return json.id
  	})
  	.catch(err => console.error('error:' + err));
  
  
  const createCustomerCardUrl = 'https://pg-sandbox.paymaya.com/payments/v1/customers/${customerIdFromMayaVault}/cards';
  	const options = {
  		headers: {
    		'Content-Type': 'application/json',
    		'Authorization': `Basic ${btoa('SECRET_KEY')}`
  		},
			method: 'POST',
			body: {
     		paymentTokenId,
     		redirectUrl: {
    			success: 'http://localhost:8080/success',
    			failure: 'http://localhost:8080/failure',
    			cancel: 'http://localhost:8080/cancel',
  			}
    	}
		};

	fetch(createCustomerCardUrl, options)
  	.then(res => res.json())
  	.then(json => {
    	const cardToken = json.cardToken
      // Your code to keep the cardToken on your application
      
   		response.redirect(303, json.verificationUrl)
  	})
  	.catch(err => console.error('error:' + err));
  
});

app.listen(8080, () => console.log(`Listening on port ${8080}!`));

You will notice that linking of customer to their credit card will return 2 items: cardToken and verificationUrl. Your application should redirect to the verificationUrl in order to trigger user authentication which will depend on the issuing bank's 3DS authentication.

Verification

There are 2 flows to verifying the linked card: through a test charge of Php 10.00 or through payment of their current transaction.

Through a test charge

From the successful call of the endpoint, your application should be redirected to the verificationUrl from the response data to continue the verification process.

🚧

Test Charge

We will be charging Php 10 to the customer's card. This amount will be automatically be refunded back.

Through payment of current transaction

Initiate the payment of the current customer transaction through Create Customer Payment endpoint. The response of the endpoint will give you a new verificationUrl that your application should redirect to.

📘

Quick test #1

To test out your card linking

  1. Input card details using one of our test cards
  2. Click the "Link a card" button.
  3. You are redirected to Issuing Bank's verification page.
  4. On successful verification, your customer will be redirected to the success page.

Step 5 Creating the subscription schedule

During this stage, you must have the following values: cardToken and customerId obtained from Maya Card Payment Vault.

To create a subscription, you will need to have the totalAmount and the schedule of the subscription ready.

{
    "description": "Sample subscription",
    "totalAmount": {
        "amount": "1.00",
        "currency": "PHP"
    },
    "interval": "DAY",
    "intervalCount": 1,
    "startDate": "YYYY-MM-DD"
}
FieldAcceptable ValuesDescription
interval(string) DAY, MONTH, YEARBehavior of the interval (daily, monthly, yearly)
intervalCount(integer) 1, 3, 5Number of intervals before the next occurrence

Example:

Daily: intervalCount = 1; interval = 'DAY'

Every 15 days: intervalCount = 15; interval = 'DAY'

Monthly: intervalCount = 1; interval = 'MONTH'

Quarterly: intervalCount = 3; interval = 'MONTH'

Annual: intervalCount = 1; interval = 'YEAR'

Your server side application will then pass the subscription configuration to the Create Subscription endpoint

const express = require('express');
const app = express();
const fetch = require('node-fetch');

async app.post('/create-subscription', async (req, res) => {

	const url = `https://pg-sandbox.paymaya.com/payments/v1/customers/${customerId}/cards/${cardToken}/subscriptions`;
	const options = {
  	method: 'POST',
  	headers: {Accept: 'application/json', 'Content-Type': 'application/json'},
    body: req.body
	};

	fetch(url, options)
  	.then(res => res.json())
  	.then(json => console.log(json))
  	.catch(err => console.error('error:' + err));
  
  res.send('Subscription Created.');
});
app.listen(8080, () => console.log(`Listening on port ${8080}!`));

📘

Subscriptions are scheduled every 11:00pm (GMT+8)

Vault will attempt to charge payments every 11:00pm (GMT+8). If the payment fails, the subscription will become inactive. Inactive Subscriptions will not be charged.