PlutoPay API Reference
The PlutoPay API is a RESTful interface for processing payments, managing terminals, and handling all aspects of your payment infrastructure. Use it to accept in-person and online payments, manage customers, configure webhooks, and more.
Base URL
https://plutopayus.com/api/v1
Quick Example
# Create a payment curl https://plutopayus.com/api/v1/transactions \ -H "Authorization: Bearer sk_live_your_secret_key" \ -H "Content-Type: application/json" \ -d '{ "amount": 2500, "currency": "usd", "description": "Order #1234" }'
Health Check
Returns the API status, version, and current server timestamp. No authentication required.
Authentication
The PlutoPay API uses API keys to authenticate requests. You can manage your API keys from the Dashboard → API Keys section.
Each merchant has two types of keys:
| Key Type | Prefix | Usage |
|---|---|---|
| Secret Key | sk_live_ / sk_test_ |
Server-side. Full access to all API endpoints. |
| Publishable Key | pk_live_ / pk_test_ |
Client-side. Limited access (e.g., creating connection tokens). |
Include your secret key in the Authorization header as a Bearer token:
curl https://plutopayus.com/api/v1/merchant \ -H "Authorization: Bearer sk_live_your_secret_key"
Keep your secret keys secure. Never expose them in client-side code, public repositories, or browser requests. Use publishable keys for frontend integrations.
Errors
The API uses standard HTTP status codes and returns errors in a consistent format:
{
"error": {
"type": "payment_error",
"message": "Insufficient funds."
}
}
| Status | Meaning |
|---|---|
200 | Success |
201 | Created successfully |
400 | Bad request — invalid parameters |
401 | Unauthorized — missing or invalid API key |
403 | Forbidden — insufficient permissions |
404 | Not found |
422 | Validation error |
500 | Server error |
Error Types
| Type | Description |
|---|---|
authentication_error | Invalid or missing API key |
payment_error | Payment processing failed |
capture_error | Failed to capture an authorized payment |
cancel_error | Failed to cancel a payment |
terminal_error | Terminal operation failed |
invalid_request | Request parameters are invalid |
Pagination
List endpoints return paginated results. Use the page and size parameters to control pagination.
| Parameter | Default | Description |
|---|---|---|
page | 1 | Page number |
size | 10 | Items per page (max 100) |
# Get page 2 with 25 items per page curl https://plutopayus.com/api/v1/transactions?page=2&size=25 \ -H "Authorization: Bearer sk_live_..."
Paginated responses include metadata:
{
"data": [...],
"meta": {
"current_page": 2,
"last_page": 5,
"per_page": 25,
"total": 112
}
}
Idempotency
To safely retry requests without processing them twice, include an idempotency_key
in the request body. If a transaction with the same key already exists, the existing transaction
is returned instead of creating a new one.
curl https://plutopayus.com/api/v1/transactions \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "amount": 5000, "currency": "usd", "idempotency_key": "order_12345_attempt_1" }'
Test Mode
PlutoPay provides a full sandbox environment for development. Use your test API keys
(sk_test_...) to create test transactions that don't process real payments.
Test mode mirrors production behavior exactly. All API endpoints, webhook events, and terminal flows work identically in both modes.
Merchant
Retrieve information about the authenticated merchant account.
Response
{
"id": "019c374b-0df7-7033-af02-9c7357f7890e",
"business_name": "Nexo Barbershop",
"display_name": "Nexo",
"email": "info@nexobarbershop.com",
"phone": "+1234567890",
"country": "US",
"default_currency": "usd",
"status": "active",
"kyc_status": "verified",
"test_mode": false,
"created_at": "2026-02-07T09:30:56+00:00"
}
Transactions
Transactions represent payments processed through PlutoPay. You can create, retrieve, capture, cancel, and refund transactions.
Endpoints
Create a Transaction
Create a new payment. All amounts are in the smallest currency unit (e.g., cents for USD).
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | integer | Yes | Amount in cents (min: 50) |
currency | string | No | Three-letter ISO code. Defaults to merchant's currency. |
payment_method | string | No | Payment method ID |
payment_method_type | string | No | card, wallet, bank_transfer, terminal |
confirm | boolean | No | Immediately confirm the payment |
capture_method | string | No | automatic or manual |
customer_id | uuid | No | Attach payment to a customer |
description | string | No | Internal description (max 500) |
receipt_email | string | No | Email for the receipt |
metadata | object | No | Key-value metadata |
idempotency_key | string | No | Unique key for idempotent requests |
# Create a payment curl -X POST https://plutopayus.com/api/v1/transactions \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "amount": 2500, "currency": "usd", "payment_method_type": "card", "description": "Haircut + Beard Trim", "metadata": { "order_id": "ORD-1234" } }'
Transaction Object
{
"id": "019c3770-a922-7219-a12d-7297ae5bfbc3",
"reference": "txn_khk3BqXBIoC8IeJhrnpF",
"type": "payment",
"status": "succeeded",
"amount": 2500,
"amount_formatted": "$25.00",
"amount_refunded": 0,
"currency": "usd",
"payment_method_type": "terminal",
"description": "Haircut + Beard Trim",
"customer_id": null,
"terminal_id": "019c3770-...",
"metadata": { "order_id": "ORD-1234" },
"captured_at": "2026-02-16T16:18:00+00:00",
"created_at": "2026-02-16T16:18:00+00:00"
}
Transaction Statuses
| Status | Description |
|---|---|
pending | Payment created, awaiting confirmation |
succeeded | Payment successfully completed |
failed | Payment was declined or failed |
canceled | Payment was canceled before completion |
refunded | Full refund issued |
partially_refunded | Partial refund issued |
requires_capture | Authorized, waiting to be captured |
List Transactions
Retrieve a list of transactions with optional filters:
| Parameter | Description |
|---|---|
search | Search by reference, description, or receipt email |
status | Filter by status |
payment_method_type | Filter by method type |
date_from | Filter from date (YYYY-MM-DD) |
date_to | Filter to date (YYYY-MM-DD) |
sortField | Sort by field (e.g., amount, created_at) |
sortOrder | asc or desc |
Capture a Transaction
Capture a payment that was created with capture_method: manual.
curl -X POST https://plutopayus.com/api/v1/transactions/{id}/capture \ -H "Authorization: Bearer sk_live_..." \ -d '{ "amount": 2000 }' # Optional: capture less than authorized
Cancel a Transaction
Cancel a pending or uncaptured payment.
curl -X POST https://plutopayus.com/api/v1/transactions/{id}/cancel \ -H "Authorization: Bearer sk_live_..."
Customers
Manage your customer records. Customers can be linked to transactions for tracking and reporting.
Create a Customer
| Parameter | Type | Description |
|---|---|---|
email | string | Customer email |
name | string | Full name |
phone | string | Phone number |
external_id | string | Your system's customer ID |
address_line1 | string | Street address |
city | string | City |
state | string | State / Region |
postal_code | string | ZIP / Postal code |
country | string | Two-letter country code |
metadata | object | Key-value metadata |
curl -X POST https://plutopayus.com/api/v1/customers \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "name": "John Smith", "email": "john@example.com", "phone": "+1 555-0123" }'
List Filters
| Parameter | Description |
|---|---|
search | Search by name, email, or phone |
email | Filter by exact email |
country | Filter by country code |
Refunds
Create full or partial refunds on completed transactions.
curl -X POST https://plutopayus.com/api/v1/transactions/{id}/refunds \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "amount": 1000 }'
If no amount is specified, a full refund is issued. The refund amount cannot exceed the original transaction amount minus any previous refunds.
Terminals
Manage your POS terminal fleet — register, monitor, and configure physical readers.
Register a Terminal
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the terminal |
registration_code | string | No | Code from the terminal device for pairing |
location_name | string | No | Store or branch name |
location_address | string | No | Physical address |
List Filters
| Parameter | Description |
|---|---|
status | online, offline, pairing |
location_name | Filter by location (partial match) |
Terminal Payments
Process in-person payments using your POS terminals. PlutoPay supports both client-driven (SDK) and server-driven payment flows.
Connection Token
Generate a connection token for the Terminal SDK. Required to initialize the reader in your client app.
Create Terminal Payment
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | integer | Yes | Amount in cents |
currency | string | No | Defaults to merchant's currency |
terminal_id | uuid | No | Specific terminal to use |
description | string | No | Payment description |
customer_id | uuid | No | Link to a customer |
Process Payment (Server-Driven)
Push a payment to a specific reader for collection. The reader will prompt the customer to tap/insert their card.
| Parameter | Type | Required | Description |
|---|---|---|---|
payment_intent_id | string | Yes | The payment intent ID from create-payment |
reader_id | string | Yes | The reader's processor terminal ID |
Simulate Payment (Test Mode)
Simulate a card present on a test reader. Only available in test mode.
List Readers
Get all terminal readers for the authenticated merchant with their current status.
Payouts
View payout records. Payouts represent transfers of funds from PlutoPay to your bank account.
List Filters
| Parameter | Description |
|---|---|
status | paid, pending, in_transit, failed |
Disputes
View disputes (chargebacks) filed against transactions.
List Filters
| Parameter | Description |
|---|---|
status | needs_response, under_review, won, lost |
Webhooks
PlutoPay sends real-time event notifications to your server via webhooks. Configure endpoints to receive events like successful payments, refunds, terminal status changes, and more.
Event Types
| Event | Description |
|---|---|
payment.succeeded | A payment was successfully completed |
payment.failed | A payment attempt failed |
payment.canceled | A payment was canceled |
refund.created | A refund was issued |
dispute.created | A dispute was opened |
payout.paid | A payout was sent to your bank |
payout.failed | A payout failed |
terminal.connected | A terminal came online |
terminal.disconnected | A terminal went offline |
Webhook Payload
{
"id": "evt_1234567890",
"type": "payment.succeeded",
"created_at": "2026-02-16T16:18:00+00:00",
"data": {
"id": "019c3770-a922-...",
"reference": "txn_khk3BqXBIoC8IeJhrnpF",
"amount": 2500,
"currency": "usd",
"status": "succeeded"
}
}
Verifying Signatures
Every webhook request includes a X-PlutoPay-Signature header containing an
HMAC-SHA256 signature. Verify this to ensure the request came from PlutoPay.
# Compute the expected signature expected = HMAC-SHA256(webhook_secret, request_body) # Compare with the header if header_signature == expected: # Signature valid ✓
Retry Policy
If your endpoint returns a non-2xx status code, PlutoPay retries with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry | 24 hours |
After 5 failed attempts, the endpoint is marked as failing and you'll be notified.
Webhook Endpoints
Programmatically manage your webhook endpoint subscriptions.
Create an Endpoint
| Parameter | Type | Required | Description |
|---|---|---|---|
url | string | Yes | HTTPS URL to receive events |
events | array | No | Specific event types to subscribe to. Omit for all events. |
description | string | No | Description for your reference |
curl -X POST https://plutopayus.com/api/v1/webhook-endpoints \ -H "Authorization: Bearer sk_live_..." \ -H "Content-Type: application/json" \ -d '{ "url": "https://yourapp.com/webhooks/plutopay", "events": ["payment.succeeded", "refund.created"], "description": "Production webhook" }'
The webhook secret is only returned when creating the endpoint. Store it securely — you'll need it to verify webhook signatures.
Test an Endpoint
Send a test event to verify your endpoint is receiving and processing webhooks correctly.
curl -X POST https://plutopayus.com/api/v1/webhook-endpoints/{id}/test \ -H "Authorization: Bearer sk_live_..."
Checkout Sessions
Checkout Sessions let you create a PlutoPay-hosted payment page. Redirect your customer to the checkout URL and we handle the rest — payment collection, validation, and confirmation.
Create a Checkout Session
/v1/checkout/sessions
| Parameter | Type | Required | Description |
|---|---|---|---|
amount | integer | Yes | Amount in cents (e.g. 2500 = $25.00) |
currency | string | No | 3-letter ISO code. Default: merchant currency |
description | string | No | What the customer is paying for |
success_url | string | No | Redirect URL after successful payment |
cancel_url | string | No | Redirect URL if customer cancels |
customer_email | string | No | Pre-fill the email on checkout |
collect_email | boolean | No | Show email field on checkout. Default: false |
collect_name | boolean | No | Show name field on checkout. Default: false |
metadata | object | No | Key-value pairs for your reference |
Example Request
curl -X POST https://plutopayus.com/api/v1/checkout/sessions \
-H "Authorization: Bearer sk_live_your_secret_key" \
-H "Content-Type: application/json" \
-d '{
"amount": 2500,
"currency": "usd",
"description": "Premium Haircut",
"success_url": "https://yoursite.com/success",
"cancel_url": "https://yoursite.com/cancel",
"collect_email": true
}'Response
{
"id": "019c8975-d9d8-72da-8262-1eb563a4dd41",
"reference": "cs_aBcDeFgHiJkLmNoPqRsT",
"url": "https://plutopayus.com/pay/cs_aBcDeFg...",
"amount": 2500,
"currency": "usd",
"status": "open",
"expires_at": "2026-02-23T10:30:00+00:00",
"transaction_id": "019c8975-d9d5-7220-a4f1-..."
}Redirect your customer to the url in the response. After payment, they'll be redirected to your success_url with ?checkout_ref=cs_xxx appended.
List Checkout Sessions
/v1/checkout/sessions
Returns a paginated list of your checkout sessions. Supports status, page, and per_page query parameters.
Retrieve a Checkout Session
/v1/checkout/sessions/{id}
Retrieves the details of a checkout session by its ID.
Payment Links
Payment Links are long-lived checkout sessions designed for sharing via SMS, WhatsApp, email, or social media. They default to a 7-day expiration instead of 30 minutes.
You can create Payment Links from the Dashboard → Payment Links page, or via the Checkout Sessions API with a longer expiration.
Dashboard Features
- Create links with custom amounts and descriptions
- Share via WhatsApp, Email, or SMS with one click
- Track link status (Active, Paid, Expired)
- Deactivate links that are no longer needed
- Copy link URL to clipboard
PlutoPay.js SDK
PlutoPay.js is a lightweight JavaScript library that lets you securely collect payment details on your website. It renders a PCI-compliant payment form that accepts cards, Apple Pay, Google Pay, Cash App Pay, Klarna, and more.
Installation
Include the script in your HTML:
<script src="https://plutopayus.com/js/plutopay.js"></script>Initialize
// Initialize with your publishable key
const plutopay = PlutoPay('pk_live_your_publishable_key');Quick Start — Accept a Payment in 3 Steps
1. Create a Payment Intent (server-side)
curl -X POST https://plutopayus.com/api/v1/payment-intents \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"amount": 2500,
"currency": "usd",
"description": "Order #1234"
}'
// Response includes client_secret:
// "client_secret": "pi_xxx_secret_xxx"2. Mount the Payment Form (client-side)
const form = await plutopay.mountPaymentForm({
clientSecret: 'pi_xxx_secret_xxx', // from step 1
container: '#payment-form',
accountId: 'acct_xxx', // your PlutoPay account ID
});3. Submit the Payment
document.getElementById('pay-btn').addEventListener('click', async () => {
const result = await form.submit({
return_url: 'https://yoursite.com/payment/success',
});
if (result.success) {
window.location.href = '/success';
} else {
alert(result.error);
}
});Payment Form Reference
The mountPaymentForm() method returns a form controller with these methods:
| Method | Description |
|---|---|
form.submit(options) | Submit the payment. Returns { success, error, paymentIntent, status } |
form.destroy() | Remove the payment form from the DOM |
form.element | Access the underlying payment element instance |
Submit Options
| Option | Type | Description |
|---|---|---|
return_url | string | URL to redirect after 3D Secure or redirect-based payments |
receipt_email | string | Email to send the payment receipt to |
redirect | string | "if_required" (default) or "always" |
Appearance Customization
const form = await plutopay.mountPaymentForm({
clientSecret: '...',
container: '#payment-form',
accountId: 'acct_xxx',
appearance: {
theme: 'default', // 'default', 'night', 'flat'
variables: {
colorPrimary: '#0B1437',
fontFamily: 'Inter, sans-serif',
borderRadius: '8px',
},
rules: {
'.Input': { border: '1.5px solid #cfd7df' },
'.Input:focus': { borderColor: '#0B1437' },
}
}
});Full HTML Example
<!DOCTYPE html>
<html>
<head>
<script src="https://plutopayus.com/js/plutopay.js"></script>
</head>
<body>
<h1>Pay $25.00</h1>
<div id="payment-form"></div>
<button id="pay-btn">Pay Now</button>
<div id="message"></div>
<script>
(async () => {
const plutopay = PlutoPay('pk_live_xxx');
const form = await plutopay.mountPaymentForm({
clientSecret: 'pi_xxx_secret_xxx',
container: '#payment-form',
accountId: 'acct_xxx',
});
document.getElementById('pay-btn').onclick = async () => {
const btn = document.getElementById('pay-btn');
btn.disabled = true;
btn.textContent = 'Processing...';
const result = await form.submit({
return_url: window.location.href,
});
if (result.success) {
document.getElementById('message').textContent = 'Payment successful!';
} else {
document.getElementById('message').textContent = result.error;
btn.disabled = false;
btn.textContent = 'Pay Now';
}
};
})();
</script>
</body>
</html>© 2026 PlutoPay by Sadeim Inc. All rights reserved.