Quick start

The fastest path to accepting your first payment via the Payments API — step-by-step from creating a Payment Intent to handling the result.

Overview

This guide walks you through the fastest path to a completed payment: a card payment via the Payment Intent workflow. By the end, you'll have working code that creates a Payment Intent, collects card details client-side, attaches them, handles 3D Secure authentication, and confirms success via webhook.

This is a single happy path — no branching, no multiple methods. Once you've completed this, see the Cards and other payment method pages to expand your integration.


Before you start

You need:

  • A PayMongo account with an activated merchant profile
  • Your secret API key and public API key from the PayMongo dashboard
  • A backend server (any language) that can make HTTPS requests
  • A frontend that can run JavaScript

All examples in this guide use test API keys. No real money moves. See Testing for test card numbers.


Step 1 — Create a Payment Intent (server-side)

From your backend, call the Create Payment Intent endpoint using your secret API key.

const response = await fetch('https://api.paymongo.com/v1/payment_intents', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Basic ' + btoa('sk_test_YOUR_SECRET_KEY:')
  },
  body: JSON.stringify({
    data: {
      attributes: {
        amount: 10000,
        currency: 'PHP',
        payment_method_allowed: ['card'],
        description: 'Order #1234'
      }
    }
  })
});
const intent = await response.json();

amount is in centavos. 10000 = PHP 100.00.

Save the id and send the client_key from the response to your frontend. The client_key is a short-lived token that lets your frontend operate on this specific Payment Intent without exposing your secret key.


Step 2 — Collect card details and create a Payment Method (client-side)

On your frontend, use your public API key to create a Payment Method from the card details the customer enters. Never send card numbers to your backend.

const response = await fetch('https://api.paymongo.com/v1/payment_methods', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Basic ' + btoa('pk_test_YOUR_PUBLIC_KEY:')
  },
  body: JSON.stringify({
    data: {
      attributes: {
        type: 'card',
        details: {
          card_number: '4343434343434345',
          exp_month: 12,
          exp_year: 2030,
          cvc: '123'
        },
        billing: {
          name: 'Juan dela Cruz',
          email: '[email protected]',
          phone: '09171234567',
          address: {
            line1: '123 Main Street',
            city: 'Manila',
            state: 'Metro Manila',
            postal_code: '1000',
            country: 'PH'
          }
        }
      }
    }
  })
});
const paymentMethod = await response.json();

Save the Payment Method id from the response.


Step 3 — Attach the Payment Method to the Payment Intent (client-side)

Still on your frontend, attach the Payment Method using the client_key from Step 1.

const attachResponse = await fetch(
  `https://api.paymongo.com/v1/payment_intents/${paymentIntentId}/attach`,
  {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Basic ' + btoa('pk_test_YOUR_PUBLIC_KEY:')
    },
    body: JSON.stringify({
      data: {
        attributes: {
          payment_method: paymentMethodId,
          client_key: clientKey,
          return_url: 'https://yoursite.com/payment/complete'
        }
      }
    })
  }
);
const intent = await attachResponse.json();

Step 4 — Handle the next action

Check the status in the response:

awaiting_next_action — 3D Secure authentication is required. Redirect the customer to the URL in next_action.redirect.url:

if (intent.data.attributes.status === 'awaiting_next_action') {
  const redirectUrl = intent.data.attributes.next_action.redirect.url;
  window.location.href = redirectUrl;
}

After the customer completes 3DS authentication, they are redirected to your return_url. Retrieve the Payment Intent server-side using the payment_intent_id query parameter to check the final status.

succeeded — Payment is complete. No redirect needed.

awaiting_payment_method — An error occurred. Check last_payment_error for the reason and let the customer retry.


Step 5 — Confirm success via webhook

In production, confirm payment outcomes via webhooks rather than relying solely on the redirect. Set up a webhook endpoint in your dashboard that listens for payment.paid and payment.failed.

When payment.paid fires, the data.attributes.payment_intent_id in the event body matches the Payment Intent ID from Step 1. Use this to fulfill the order on your end.


What's next