Accepting a Payment

Overview

Building an integration with Payment Intents workflow only involves three actions: creating the Payment Intent, creating the Payment Method, and attaching a Payment Method to a Payment Intent.

The Payment Intent Workflow

  1. When a customer is ready to complete their purchase, your application creates a Payment Intent and a Payment Method to record the details of a transaction and payment option.

    A Payment Intent resource represents a single shopping cart or customer session in your application. The Payment Intent holds information such as the supported payment methods, the amount to collect, and the currency.

    A Payment Method resource resource represents the billing details of the customer and any information specific for the payment method. Examples include credit card information, name, email, and address.

  2. Your application combines the two by attaching the Payment Intent to the Payment Method. For payment methods like Card and E-wallets, this produces the authorization URL that needs to be presented to the customer. For other payment methods like QR Ph, this produces a QR image that the customer needs to scan and pay.

  3. The customer authorizes and completes the transaction.

940

Sample Card Workflow

Implementation

1. Creating a Payment Intent from the server-side

To start receiving payments with the Payment Intent workflow, you must create a Payment Intent first by calling the Create a Payment Intent API. You must create your Payment Intent from your backend using your secret API key then send the client_key of the response to the client-side. This client_key will be used to attach a payment method to the payment intent. In this step, the payment intent's status will be awaiting_payment_method. Store the Payment Intent ID.

2. Create a Payment Method from the client-side

Collect billing Information and other information required by the payment method from the client-side with the use of forms. We do not recommend storing this information on your server. Send this information over to us and we'll handle the rest! Create a payment method by calling our Create A Payment Method API: https://developers.paymongo.com/reference#create-a-paymentmethod. Store the Payment Method ID. 

NOTE: Do not send the credit card information to your backend, sending the information to your backend requires your platform to conform with PCI-DSS regulations.

3. Attach the Payment Intent to the Payment Method

Attach the Payment Intent to the Payment Method by calling our Attach API. Attaching the Payment Intent can be done on the client side or the server side. The implementation is completely up to the merchant's choice.

If calling the Attach API will be on the client side, you need to use the client_key found in the Payment Intent resource to serve as the identifier of the Payment Intent in the attach endpoint. You will also need to use your Public API Key if calling the Attach API from the client side. Do not use your Secret API Keys if the call will be done on the client side.

If calling the Attach API will be on the server side, you may use your Secret API Keys and the client_keywill not be required.

We do recommend that for those implementing our Save Card, that the Attach API call is done on the server side to lessen the amount of routes that are needed to be developed.

Once the Payment Method is attached, the Payment Intent status immediately transitions to awaiting_next_action. Other statuses for Payment Intent includes awaiting_payment_method , processing or succeeded. You can check the status of the Payment Intent from the JSON response of the attach payment method endpoint.

4. Redirecting the customer for authentication

If the attach returns an awaiting_next_action status, it indicates that your customer needs to authenticate the transaction. The response will include a redirect URL where the customer can complete this step. Redirect the customer to this URL to proceed with authentication. Once the user successfully authenticates the transaction, they will be redirected to the return_url specified during the Attach API call.

// The example is using axios as the REST client on the client-side.


// This PaymentMethod ID must be created before the attach action. This is just a sample value to represent a PaymentMethod
var paymentMethodId = 'pm_ajeDG2y6WgnrCXaamWFmPUw2';

// PaymentIntent client_key example
var clientKey = 'pi_1JvFbEiRRnh2fsUE5nJ2F1z7_client_mpe6tJkgaX3pSoiYeSp1AbEU';

// Get the payment intent id from the client key
var paymentIntentId = clientKey.split('_client')[0];

axios.post(
  'https://api.paymongo.com/v1/payment_intents/' + paymentIntentId + '/attach',
  {
    data: {
      attributes: {
        client_key: clientKey,
        payment_method: paymentMethodId
      }
    }
  },
  {
    headers: {
      // Base64 encoded public PayMongo API key.
      Authorization: `Basic ${window.btoa(key)}`
    }
	}
).then(function(response) {
  var paymentIntent = response.data.data;
  var paymentIntentStatus = paymentIntent.attributes.status;
  
  if (paymentIntentStatus === 'awaiting_next_action') {
    // Render your modal for the redirect since the next_action has a value. You can access the next action via paymentIntent.attributes.next_action.
  } else if (paymentIntentStatus === 'succeeded') {
    // You already received your customer's payment. You can show a success message from this condition.
  } else if(paymentIntentStatus === 'awaiting_payment_method') {
    // The PaymentIntent encountered a processing error. You can refer to paymentIntent.attributes.last_payment_error to check the error and render the appropriate error message.
  }  else if (paymentIntentStatus === 'processing'){
    // You need to requery the PaymentIntent after a second or two. This is a transitory status and should resolve to `succeeded` or `awaiting_payment_method` quickly.
  }
})
🚧

GCash Deep Links: Important Note for App-Based Merchants

If your customer chooses GCash as the payment method and you are using a mobile app-based checkout experience (e.g., within your iOS or Android app), GCash’s new payment authentication flow includes a deeplink that triggers an “Open in GCash” button. This button attempts to open the GCash mobile app directly so the customer can complete their payment.

To ensure this works correctly:

  • iOS and Android apps must support gcash:// deeplinks.
  • Without proper handling, the “Open in GCash” button will not work (e.g., it may do nothing or show an error).
  • Customers can still scan the QR code, but the in-app redirection flow will not function as intended.

For implementation instructions, see our Handling GCash deep link Guide.


After the user is redirected back to your specified URL, query the status of the Payment Intent to determine and display the appropriate message to the user.

// Example function to check the payment intent status after redirect
function checkPaymentIntentStatus(paymentIntentId, clientKey, apiKey) {
  axios.get(
    `https://api.paymongo.com/v1/payment_intents/${paymentIntentId}?client_key=${clientKey}`,
    {
      headers: {
        // Base64 encoded public PayMongo API key.
        Authorization: `Basic ${window.btoa(apiKey)}`
      }
    }
  ).then(function(response) {
    const paymentIntent = response.data.data;
    const paymentIntentStatus = paymentIntent.attributes.status;

    if (paymentIntentStatus === 'succeeded') {
      // Payment successful — show a success message
    } else if (paymentIntentStatus === 'awaiting_payment_method') {
      // Payment failed or requires action — handle errors accordingly
    } else if (paymentIntentStatus === 'processing') {
      // Transitory status — you may want to retry checking after a short delay
    }
  }).catch(error => {
    // Handle request errors here
  });
}

// Call this function on your redirect page, e.g.:
const paymentIntentId = 'pi_1JvFbEiRRnh2fsUE5nJ2F1z7'; // Replace with real ID
const clientKey = 'pi_1JvFbEiRRnh2fsUE5nJ2F1z7_client_mpe6tJkgaX3pSoiYeSp1AbEU'; // Replace with real client key
const apiKey = 'your_public_api_key_here'; // Replace with your API key

checkPaymentIntentStatus(paymentIntentId, clientKey, apiKey);

awaiting_payment_method means there are errors after attaching the Payment Method to the PaymentIntent. You can check the attribute last_payment_error from the response. If this occurs, the customer can try to input their billing information again.

processing is a transitory status that indicates that the payment is being processed. This status will eventually resolve to succeeded or awaiting_payment_method. If this occurs, you should requery the status of the PaymentIntent in 1-2 seconds.

succeeded means you received the payment of the customer and you can show a success message after this happened.

Whenever you will attach a Payment Method to a Payment Intent and the Payment Intent succeeds or you encountered a payment error, a Payment is automatically created for you. You can verify if you received the payment by going to the Payments module of your dashboard or you can also retrieve the Payment Intent using your Secret API Key and check the payments attribute.

5. Finish

Get notified when you have successful or failed transactions by using webhooks. To monitor the transition of the Payment Intent from your backend, you could be notified for successful and failed payments by listening to payment.paid and payment.failed events by registering your webhook endpoint using our Webhook API.

🚧

Webhooks

You should not create a webhook in your code. You can try using API tools such as Postman or curl to create your webhook once. Please take note that you should not create multiple webhooks for every source that will be created. One webhook with events payment.paid and payment.failed is enough to receive the payment information.

You can determine if a payment is successful or not by checking the event type or the status of the payment intent.

You may also watch this video guide: