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

GET /v1/health

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 TypePrefixUsage
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."
  }
}
StatusMeaning
200Success
201Created successfully
400Bad request — invalid parameters
401Unauthorized — missing or invalid API key
403Forbidden — insufficient permissions
404Not found
422Validation error
500Server error

Error Types

TypeDescription
authentication_errorInvalid or missing API key
payment_errorPayment processing failed
capture_errorFailed to capture an authorized payment
cancel_errorFailed to cancel a payment
terminal_errorTerminal operation failed
invalid_requestRequest parameters are invalid

Pagination

List endpoints return paginated results. Use the page and size parameters to control pagination.

ParameterDefaultDescription
page1Page number
size10Items 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.

GET /v1/merchant

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

GET /v1/transactions
POST /v1/transactions
GET /v1/transactions/{id}
POST /v1/transactions/{id}/capture
POST /v1/transactions/{id}/cancel

Create a Transaction

Create a new payment. All amounts are in the smallest currency unit (e.g., cents for USD).

ParameterTypeRequiredDescription
amountintegerYesAmount in cents (min: 50)
currencystringNoThree-letter ISO code. Defaults to merchant's currency.
payment_methodstringNoPayment method ID
payment_method_typestringNocard, wallet, bank_transfer, terminal
confirmbooleanNoImmediately confirm the payment
capture_methodstringNoautomatic or manual
customer_iduuidNoAttach payment to a customer
descriptionstringNoInternal description (max 500)
receipt_emailstringNoEmail for the receipt
metadataobjectNoKey-value metadata
idempotency_keystringNoUnique 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

StatusDescription
pendingPayment created, awaiting confirmation
succeededPayment successfully completed
failedPayment was declined or failed
canceledPayment was canceled before completion
refundedFull refund issued
partially_refundedPartial refund issued
requires_captureAuthorized, waiting to be captured

List Transactions

Retrieve a list of transactions with optional filters:

ParameterDescription
searchSearch by reference, description, or receipt email
statusFilter by status
payment_method_typeFilter by method type
date_fromFilter from date (YYYY-MM-DD)
date_toFilter to date (YYYY-MM-DD)
sortFieldSort by field (e.g., amount, created_at)
sortOrderasc 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.

GET/v1/customers
POST/v1/customers
GET/v1/customers/{id}
PUT/v1/customers/{id}
DELETE/v1/customers/{id}

Create a Customer

ParameterTypeDescription
emailstringCustomer email
namestringFull name
phonestringPhone number
external_idstringYour system's customer ID
address_line1stringStreet address
citystringCity
statestringState / Region
postal_codestringZIP / Postal code
countrystringTwo-letter country code
metadataobjectKey-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

ParameterDescription
searchSearch by name, email, or phone
emailFilter by exact email
countryFilter by country code

Refunds

Create full or partial refunds on completed transactions.

POST /v1/transactions/{transaction_id}/refunds
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.

GET/v1/terminals
POST/v1/terminals
GET/v1/terminals/{id}
PUT/v1/terminals/{id}
DELETE/v1/terminals/{id}

Register a Terminal

ParameterTypeRequiredDescription
namestringYesDisplay name for the terminal
registration_codestringNoCode from the terminal device for pairing
location_namestringNoStore or branch name
location_addressstringNoPhysical address

List Filters

ParameterDescription
statusonline, offline, pairing
location_nameFilter 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

POST /v1/terminal/connection-token

Generate a connection token for the Terminal SDK. Required to initialize the reader in your client app.

Create Terminal Payment

POST /v1/terminal/create-payment
ParameterTypeRequiredDescription
amountintegerYesAmount in cents
currencystringNoDefaults to merchant's currency
terminal_iduuidNoSpecific terminal to use
descriptionstringNoPayment description
customer_iduuidNoLink to a customer

Process Payment (Server-Driven)

POST /v1/terminal/process-payment

Push a payment to a specific reader for collection. The reader will prompt the customer to tap/insert their card.

ParameterTypeRequiredDescription
payment_intent_idstringYesThe payment intent ID from create-payment
reader_idstringYesThe reader's processor terminal ID

Simulate Payment (Test Mode)

POST /v1/terminal/simulate-payment

Simulate a card present on a test reader. Only available in test mode.

List Readers

GET /v1/terminal/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.

GET/v1/payouts
GET/v1/payouts/{id}

List Filters

ParameterDescription
statuspaid, pending, in_transit, failed

Disputes

View disputes (chargebacks) filed against transactions.

GET/v1/disputes
GET/v1/disputes/{id}

List Filters

ParameterDescription
statusneeds_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

EventDescription
payment.succeededA payment was successfully completed
payment.failedA payment attempt failed
payment.canceledA payment was canceled
refund.createdA refund was issued
dispute.createdA dispute was opened
payout.paidA payout was sent to your bank
payout.failedA payout failed
terminal.connectedA terminal came online
terminal.disconnectedA 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:

AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry24 hours

After 5 failed attempts, the endpoint is marked as failing and you'll be notified.

Webhook Endpoints

Programmatically manage your webhook endpoint subscriptions.

GET/v1/webhook-endpoints
POST/v1/webhook-endpoints
GET/v1/webhook-endpoints/{id}
PUT/v1/webhook-endpoints/{id}
DELETE/v1/webhook-endpoints/{id}
POST/v1/webhook-endpoints/{id}/test

Create an Endpoint

ParameterTypeRequiredDescription
urlstringYesHTTPS URL to receive events
eventsarrayNoSpecific event types to subscribe to. Omit for all events.
descriptionstringNoDescription 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

POST /v1/checkout/sessions
ParameterTypeRequiredDescription
amountintegerYesAmount in cents (e.g. 2500 = $25.00)
currencystringNo3-letter ISO code. Default: merchant currency
descriptionstringNoWhat the customer is paying for
success_urlstringNoRedirect URL after successful payment
cancel_urlstringNoRedirect URL if customer cancels
customer_emailstringNoPre-fill the email on checkout
collect_emailbooleanNoShow email field on checkout. Default: false
collect_namebooleanNoShow name field on checkout. Default: false
metadataobjectNoKey-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

GET /v1/checkout/sessions

Returns a paginated list of your checkout sessions. Supports status, page, and per_page query parameters.

Retrieve a Checkout Session

GET /v1/checkout/sessions/{id}

Retrieves the details of a checkout session by its ID.

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:

MethodDescription
form.submit(options)Submit the payment. Returns { success, error, paymentIntent, status }
form.destroy()Remove the payment form from the DOM
form.elementAccess the underlying payment element instance

Submit Options

OptionTypeDescription
return_urlstringURL to redirect after 3D Secure or redirect-based payments
receipt_emailstringEmail to send the payment receipt to
redirectstring"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.