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
- Add more payment methods: E-wallets, QR Ph, BNPL
- Store cards for future purchases: Card Vaulting
- Set up recurring billing: Subscriptions
- Go to production: Best Practices, Testing
Updated about 4 hours ago