TEST MODE ENABLED — No payments will be charged to cards

API Documentation

Integrate Go2PAY into your application to create products, send payment requests, and manage your business programmatically.

Base URL: https://go2pay.gd/api/v1 — All endpoints are relative to this base.

Authentication

There are two ways to authenticate. Both send a token in the Authorization header, so the rest of this document applies to either.

MethodBest forNotes
API key Websites, online stores and any server that runs unattended Does not expire, can be limited to taking payments, and can be revoked on its own. Recommended.
Email and password Apps where a person signs in Returns a token good for one hour, refreshed with a second token. Unchanged and still fully supported.

API keys

A key works on every endpoint in this document. It is not only for the WooCommerce plugin: anything you can do by signing in with your email and password, you can do with a key set to Everything my account can do — without a password stored in your code, and with the ability to switch that one key off without changing anything else.

Create one while signed in at https://go2pay.gd/integration-keys, under API Keys. The key is shown once, when you create it. We store only a scrambled copy, so if you lose it you revoke it and make another.

Send it exactly like a token:

curl https://go2pay.gd/api/v1/orders \
  -H "Authorization: Bearer g2p_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Each key is created with one of two permissions:

PermissionWhat it may call
Take payments only POST /requests, GET /requests, GET /requests/{id}, GET /orders, GET /orders/{id}, GET /auth/me. Everything else is refused with 403, including refunds and anything to do with withdrawals or bank accounts.
Everything my account can do Every endpoint in this document, the same as signing in with a password.

Live keys and test keys

Keys come in two kinds, and the kind is carried in the key itself, so there is no setting to get wrong.

PrefixWhat it does
g2p_live_ Real payments against real cards. Money reaches the vendor's balance.
g2p_test_ Runs the whole flow with no money. Only test card numbers are accepted, and the resulting orders never appear in balances, sales totals, withdrawals or stock counts.

Everything else behaves identically, so the same integration code works for both: swap the key and nothing else. Test payments are clearly marked on the payment page so nobody mistakes one for a real sale.

Use these card numbers with a test key, with any future expiry date and any security code. A real card is refused on a test key.

Card numberResult
4242 4242 4242 4242Succeeds
4000 0000 0000 0002Declined
4000 0000 0000 9995Declined, insufficient funds
4000 0025 0000 3155Requires extra authentication
5555 5555 5555 4444Succeeds (Mastercard)

A real card is refused on a test key. A live key takes real cards as normal.

Which should I use? If your code runs on a server without anyone signing in — a website, a store, a script, a scheduled job — use an API key. Keep the email and password flow for apps where a person signs in, like the Go2PAY mobile app.
Keep a key to the smallest permission that works. A key set to take payments only cannot move money out of your account, so a website that is broken into cannot be used to drain it. Revoking a key stops it on the integration's very next call, and does not affect your password, your other keys, or the mobile app.

Email and password

Login with your email and password to receive an access token. This is what the mobile app uses, and nothing about it has changed.

POST /auth/login

Authenticate and receive tokens.

curl -X POST https://go2pay.gd/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "your_password"}'

Response:

{
  "success": true,
  "data": {
    "access_token": "eyJ...",
    "refresh_token": "eyJ...",
    "expires_in": 3600,
    "user": { "id": 123, "first_name": "John", "email": "you@example.com" }
  }
}

POST /auth/refresh

Refresh an expired access token using your refresh token (valid for 30 days).

curl -X POST https://go2pay.gd/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh_token": "eyJ..."}'
Using your token: Include the access token in the Authorization header on all protected requests:
Authorization: Bearer eyJ...
An API key goes in the very same header, and never needs refreshing:
Authorization: Bearer g2p_live_...

Products

Create and manage payment links for your products or services.

POST /products

Create a new product and receive a payment link.

FieldTypeRequiredDescription
titlestringYesProduct name
pricedecimalYesPrice in USD
descriptionstringNoProduct description
max_quantityintNoMax qty per order (default: 10)
quantity_availableintNoStock available (null = unlimited)
endpointurlNoWebhook URL — receives POST on payment
success_urlurlNoRedirect after successful payment
error_urlurlNoRedirect on error
purchase_notestringNoNote shown on receipt
curl -X POST https://go2pay.gd/api/v1/products \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Premium Plan",
    "price": 49.99,
    "description": "Monthly subscription",
    "endpoint": "https://mysite.com/webhook"
  }'

Response includes payment_url — share this link with customers:

{
  "success": true,
  "data": {
    "id": 123,
    "title": "Premium Plan",
    "price": 49.99,
    "payment_url": "https://go2pay.gd/123",
    ...
  }
}

GET /products

List your products. Supports ?page=1&q=search&type=product

GET /products/{id}

Get a single product with order stats and payment URL.

PUT /products/{id}

Update a product. Send only the fields you want to change.

DELETE /products/{id}

Archive (soft-delete) a product.

Payment Requests

Send a one-time payment request to a specific customer. Creates a payment link and optionally emails it.

POST /requests

Create a payment request.

FieldTypeRequiredDescription
namestringYesCustomer name
emailstringYesCustomer email
amountdecimalYesAmount in USD
phonestringNoCustomer phone
descriptionstringNoNote shown to customer
endpointurlNoWebhook URL (HTTPS only)
success_urlurlNoRedirect after payment
error_urlurlNoRedirect on error
send_emailboolNoEmail the payment link to the customer (default true)
send_receiptboolNoEmail the customer a receipt after they pay (default true; the vendor's copy always sends)
curl -X POST https://go2pay.gd/api/v1/requests \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe",
    "email": "john@example.com",
    "amount": 150.00,
    "description": "Invoice #1234",
    "send_email": true,
    "send_receipt": false
  }'
{
  "success": true,
  "data": {
    "id": 456,
    "payment_url": "https://go2pay.gd/456",
    "title": "John Doe",
    "price": 150.00,
    "email": "john@example.com",
    "email_sent": true
  }
}

send_email: false skips the payment-link email to the customer (email_sent will be false). send_receipt: false skips the customer's receipt email after they pay — use both when your site sends its own emails. The vendor's receipt copy and your webhook endpoint always fire regardless.

GET /requests

List your payment requests. Supports ?page=1&q=search

GET /requests/{id}

Get a single payment request with order stats.

DELETE /requests/{id}

Archive a payment request.

Subscriptions

Create recurring plans and manage their subscribers. A plan charges the customer's saved card automatically each billing period. Subscription charges appear in your Orders and are withdrawable like any other sale.

POST /subscriptions

Create a subscription plan. Returns a subscribe_url to share with customers.

FieldTypeRequiredDescription
namestringYesPlan name (e.g. "Gold Membership")
pricedecimalYesRecurring price in USD
billing_intervalstringYesOne of weekly, monthly, quarterly, yearly
descriptionstringNoShown on the sign-up page
trial_daysintNoFree trial length in days (default 0)
setup_feedecimalNoOne-time fee charged on the first cycle (default 0)
max_chargesintNoAuto-cancel after this many charges (null = unlimited)
pay_processing_feeboolNoAbsorb the processing fee instead of passing it to the subscriber
show_addressboolNoCollect a billing address at checkout
cancel_on_disputeboolNoAuto-cancel the subscription if a charge is disputed (default true)
success_url / cancel_urlurlNoRedirects after checkout
curl -X POST https://go2pay.gd/api/v1/subscriptions \
  -H "Authorization: Bearer eyJ..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Gold Membership",
    "price": 9.99,
    "billing_interval": "monthly",
    "trial_days": 7,
    "setup_fee": 5.00
  }'

Response includes subscribe_url — share this link (or its QR / embed card) with customers:

{
  "success": true,
  "message": "Subscription created successfully",
  "data": {
    "id": 42,
    "name": "Gold Membership",
    "price": 9.99,
    "billing_interval": "monthly",
    "trial_days": 7,
    "cancel_on_dispute": true,
    "subscribe_url": "https://go2pay.gd/subscribe/2b3c…"
  }
}

GET /subscriptions

List your plans (paginated) with subscriber and revenue counts. Supports ?page=1&limit=20&q=search&include_archived=false.

GET /subscriptions/{id}

Get a plan with its list of subscribers.

PUT /subscriptions/{id}

Update a plan. Price/interval changes apply to future cycles only. Accepts the same fields as create.

DELETE /subscriptions/{id}

Archive a plan. It stops accepting new sign-ups; existing subscribers keep billing until cancelled.

GET /subscriptions/{id}/subscribers

List a plan's subscribers (status, card, next charge date, cycles).

POST /subscriptions/subscribers/{signupId}/cancel

Cancel a subscriber — they will not be charged again.

POST /subscriptions/subscribers/{signupId}/pause

Pause a subscriber's billing (excluded from charging while paused).

POST /subscriptions/subscribers/{signupId}/resume

Resume a paused subscriber. The next charge date shifts forward by the paused duration.

Orders

View and manage orders placed through your payment links.

GET /orders

List orders. Supports ?page=1&status=PAID&q=search&product_id=123

GET /orders/{id}

Get a single order with full details.

POST /orders/{id}/refund

Refund an order through Stripe. Supports full and partial refunds; partial refunds may be repeated up to the order total.

FieldTypeRequiredDescription
amountdecimalNoAmount to refund in USD. Omit to refund the full remaining balance. Capped at the remaining balance if larger.
reasonstringNoRefund reason. duplicate, fraudulent, or requested_by_customer are passed to Stripe; any other text is stored as a note.

Send an optional Idempotency-Key header to make retries safe — repeating a request with the same key will not refund twice.

curl -X POST https://go2pay.gd/api/v1/orders/789/refund \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: refund-789-001" \
  -d '{"amount": 25.00, "reason": "requested_by_customer"}'

Response:

{
  "success": true,
  "message": "Refund processed successfully",
  "data": {
    "order_id": 789,
    "refunded_amount": 25.00,
    "total_refunded": 25.00,
    "status": "PARTIAL REFUND",
    "stripe_refund_id": "re_3Ab1Cd..."
  }
}

status is PARTIAL REFUND while a balance remains, or REFUNDED once fully refunded.

CodeMeaning
404Order not found or not owned by your account
409Order has an active dispute, or has already been withdrawn
400No payment to refund, already fully refunded, or outside the refund window
422Refund amount is not greater than zero
429Too many requests to Stripe — retry shortly

Customers

Customers are created automatically when payments are made. You can list and view them.

GET /customers

List customers with order stats. Supports ?q=search

GET /customers/{id}

Get customer detail with last 10 orders.

Webhooks & Callbacks

When a customer completes a payment, Go2PAY sends a POST request to the endpoint URL you specified when creating the product or request.

Callback Payload

The following JSON is POSTed to your endpoint after a successful payment:

{
  "order_id": 789,
  "api_order_id": "your-external-id",
  "product_id": 123,
  "status": "PAID",
  "first_name": "John",
  "last_name": "Doe",
  "email": "john@example.com",
  "phone": "473-123-4567",
  "price": 49.99,
  "qty": 1,
  "subtotal": 49.99,
  "customer_total": 52.44,
  "currency": "USD",
  "payment_id": "pi_xxx",
  "created": "2026-04-06T18:00:00+00:00"
}
Security: Callback URLs must use HTTPS and cannot point to private/loopback IPs.

Response Format

All responses follow this structure:

// Success
{
  "success": true,
  "message": "Description",
  "data": { ... }
}

// Paginated
{
  "success": true,
  "data": [ ... ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 85,
    "total_pages": 5
  }
}

// Error
{
  "success": false,
  "message": "Error description"
}

Error Codes

CodeMeaning
400Bad Request — invalid data or business rule violation
401Unauthorized — missing or invalid token, or an API key that is unknown or revoked
403Forbidden — not a vendor, account inactive, or an API key limited to taking payments was used on another endpoint
404Not Found — resource doesn't exist or isn't yours
422Validation Error — missing required fields
500Server Error — contact support

Quick Start (JavaScript)

Example 1: Create a Payment Product

// 1. Login
const auth = await fetch('https://go2pay.gd/api/v1/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email: 'you@example.com', password: 'pass' })
}).then(r => r.json());

const token = auth.data.access_token;

// 2. Create a product
const product = await fetch('https://go2pay.gd/api/v1/products', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer ' + token
  },
  body: JSON.stringify({
    title: 'Premium Plan',
    price: 49.99,
    description: 'Monthly subscription',
    max_quantity: 1,
    endpoint: 'https://mysite.com/webhook',
    success_url: 'https://mysite.com/thank-you'
  })
}).then(r => r.json());

// 3. Share the payment link with your customers
console.log(product.data.payment_url);
// → https://go2pay.gd/123

Example 2: Send a Payment Request

// Using the same token from above...

// Create a payment request and email it to the customer
const request = await fetch('https://go2pay.gd/api/v1/requests', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer ' + token
  },
  body: JSON.stringify({
    name: 'John Doe',
    email: 'john@example.com',
    amount: 150.00,
    description: 'Invoice #1234',
    endpoint: 'https://mysite.com/webhook',
    send_email: false,   // your site emails the payment link itself
    send_receipt: false  // your site emails its own receipt after payment
  })
}).then(r => r.json());

console.log(request.data.payment_url);
// → https://go2pay.gd/456
console.log(request.data.email_sent);
// → true
Need help? Contact support@go2pay.gd