Invoices
An invoice is a one-time payment request. Create it, send your
customer the payment_url, get a signed webhook when
we credit your balance.
POST /api/v1/merchant/invoices
Required scope: invoices.write. Required header: Idempotency-Key.
Body
| Field | Type | Notes |
|---|---|---|
amount | string | Decimal, e.g. "5.00". |
currency | string | Asset symbol. Must be in your allowed list. |
chain | string | Network id (tron, ethereum, base, bsc, bitcoin). |
description | string | ≤ 500 chars. Shown to the customer. |
order_id | string | ≤ 100 chars. Your internal id. Unique per merchant. |
customer_id | string | Opaque tag. Not visible to the customer. |
customer_email | string | Stored hashed. |
success_url | string | HTTPS. Customer returns here after payment. |
fail_url | string | HTTPS. Used for cancelled / expired flows. |
webhook_url | string | Per-invoice override of the merchant default. |
metadata | object | ≤ 4 KB JSON object; echoed in webhooks. |
Examples
curl
curl -X POST https://api.swapss.lol/api/v1/merchant/invoices \
-H "Authorization: Bearer sk_live_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"amount": "5.00",
"currency": "USDT",
"chain": "tron",
"description": "Order #1042",
"order_id": "1042"
}'javascript
import { randomUUID } from 'node:crypto';
async function createInvoice(payload) {
const res = await fetch('https://api.swapss.lol/api/v1/merchant/invoices', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SWAP_PAY_SECRET}`,
'Idempotency-Key': randomUUID(),
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${error.code}: ${error.message}`);
}
return res.json();
}python
import os, uuid, requests
def create_invoice(payload):
r = requests.post(
"https://api.swapss.lol/api/v1/merchant/invoices",
headers={
"Authorization": f"Bearer {os.environ['SWAP_PAY_SECRET']}",
"Idempotency-Key": str(uuid.uuid4()),
"Content-Type": "application/json",
},
json=payload,
timeout=10,
)
r.raise_for_status()
return r.json()php
<?php
function create_invoice(array $payload): array {
$ch = curl_init('https://api.swapss.lol/api/v1/merchant/invoices');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('SWAP_PAY_SECRET'),
'Idempotency-Key: ' . bin2hex(random_bytes(16)),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($status >= 300) {
throw new RuntimeException("Swap Pay error: $body");
}
return json_decode($body, true);
}go
package swappay
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"github.com/google/uuid"
)
func CreateInvoice(payload map[string]any) (map[string]any, error) {
body, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", "https://api.swapss.lol/api/v1/merchant/invoices", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("SWAP_PAY_SECRET"))
req.Header.Set("Idempotency-Key", uuid.NewString())
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil { return nil, err }
defer res.Body.Close()
var out map[string]any
if err := json.NewDecoder(res.Body).Decode(&out); err != nil { return nil, err }
if res.StatusCode >= 300 {
return nil, fmt.Errorf("swap pay: %v", out["error"])
}
return out, nil
}GET /api/v1/merchant/invoices/{public_id}
Required scope: invoices.read or invoices.write.
GET /api/v1/merchant/invoices
Cursor-paginated list. Filters: status, chain, currency, created_after, created_before, cursor, limit (1..=100, default 20).
POST /api/v1/merchant/invoices/{public_id}/cancel
Only awaiting_deposit invoices can cancel. Idempotent —
a second cancel returns 200 with the current state.
Lifecycle
An invoice walks: awaiting_deposit → seen → confirming → confirmed → paid.
The customer's hosted page subscribes to status events; your server
receives signed webhooks per transition (see webhooks).