Hex Pay Docs

Create Payment via API

Learn how to create cryptocurrency payments using the HexPay REST API

API Endpoint

POST https://api.hexpay.io/v1/payments

Optionally pass an X-Idempotency-Key header (UUID) to prevent duplicate payments on retry.

Two Modes of Payment Creation

The customer sees all payment methods enabled for your store and picks one at checkout. Use this when you want to give the customer flexibility.

The payment is created in created status. paymentDetails (deposit address and coin amount) is absent until the customer selects a method.

curl -X POST "https://api.hexpay.io/v1/payments" \
  -H "Authorization: Bearer eyJhbGciOiJFZERTQSIsImtpZCI6IjFjZDZhOTIy..." \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" \
  -d '{
    "amount": "100.00",
    "currency": "USD",
    "order_id": "order-2026-00123",
    "webhookURL": "https://merchant.com/webhooks/hexpay"
  }'
const response = await fetch("https://api.hexpay.io/v1/payments", {
  method: "POST",
  headers: {
    "Authorization": "Bearer eyJhbGciOiJFZERTQSIsImtpZCI6IjFjZDZhOTIy...",
    "Content-Type": "application/json",
    "X-Idempotency-Key": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
  },
  body: JSON.stringify({
    amount: "100.00",
    currency: "USD",
    order_id: "order-2026-00123",
    webhookURL: "https://merchant.com/webhooks/hexpay"
  })
});

const payment = await response.json();
package main

import (
  "fmt"
  "net/http"
  "io/ioutil"
  "strings"
)

func main() {
  body := strings.NewReader(`{
    "amount": "100.00",
    "currency": "USD",
    "order_id": "order-2026-00123",
    "webhookURL": "https://merchant.com/webhooks/hexpay"
  }`)

  req, _ := http.NewRequest("POST", "https://api.hexpay.io/v1/payments", body)
  req.Header.Add("Authorization", "Bearer eyJhbGciOiJFZERTQSIsImtpZCI6IjFjZDZhOTIy...")
  req.Header.Add("Content-Type", "application/json")
  req.Header.Add("X-Idempotency-Key", "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d")

  res, _ := http.DefaultClient.Do(req)
  defer res.Body.Close()
  respBody, _ := ioutil.ReadAll(res.Body)
  fmt.Println(string(respBody))
}
import requests

response = requests.post(
  "https://api.hexpay.io/v1/payments",
  json={
    "amount": "100.00",
    "currency": "USD",
    "order_id": "order-2026-00123",
    "webhookURL": "https://merchant.com/webhooks/hexpay"
  },
  headers={
    "Authorization": "Bearer eyJhbGciOiJFZERTQSIsImtpZCI6IjFjZDZhOTIy...",
    "Content-Type": "application/json",
    "X-Idempotency-Key": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
  }
)

payment = response.json()

Response — payment in created status:

{
  "id": "019327c6-2058-7901-b234-56789abcdeff",
  "status": "created",
  "order_id": "order-2026-00123",
  "amount": "100.00",
  "currency": "USD",
  "checkoutURL": "https://payment.hexpay.io/019327c6-2058-7901-b234-56789abcdeff",
  "timer": {
    "createdAt": "2026-01-20T10:00:00Z",
    "expiresAt": "2026-01-20T11:00:00Z"
  }
}

Redirect the customer to checkoutURL — they will see all available payment methods and pick one. paymentDetails appears once they select a method and the payment moves to pending.


2. Preselected Method

You specify the exact coin and chain upfront. The server resolves the deposit address immediately — the customer skips method selection and goes straight to the deposit screen.

The payment is created directly in pending status with paymentDetails already populated.

Use coin and chain symbol values from GET /v1/payment-methods. Values are case-sensitive.

curl -X POST "https://api.hexpay.io/v1/payments" \
  -H "Authorization: Bearer eyJhbGciOiJFZERTQSIsImtpZCI6IjFjZDZhOTIy..." \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" \
  -d '{
    "amount": "100.00",
    "currency": "USD",
    "payment_options": {
      "methods": [{ "coin": "USDT", "chain": "TON" }]
    },
    "order_id": "order-2026-00124",
    "webhookURL": "https://merchant.com/webhooks/hexpay"
  }'
const response = await fetch("https://api.hexpay.io/v1/payments", {
  method: "POST",
  headers: {
    "Authorization": "Bearer eyJhbGciOiJFZERTQSIsImtpZCI6IjFjZDZhOTIy...",
    "Content-Type": "application/json",
    "X-Idempotency-Key": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
  },
  body: JSON.stringify({
    amount: "100.00",
    currency: "USD",
    payment_options: {
      methods: [{ coin: "USDT", chain: "TON" }]
    },
    order_id: "order-2026-00124",
    webhookURL: "https://merchant.com/webhooks/hexpay"
  })
});

const payment = await response.json();
package main

import (
  "fmt"
  "net/http"
  "io/ioutil"
  "strings"
)

func main() {
  body := strings.NewReader(`{
    "amount": "100.00",
    "currency": "USD",
    "payment_options": {
      "methods": [{ "coin": "USDT", "chain": "TON" }]
    },
    "order_id": "order-2026-00124",
    "webhookURL": "https://merchant.com/webhooks/hexpay"
  }`)

  req, _ := http.NewRequest("POST", "https://api.hexpay.io/v1/payments", body)
  req.Header.Add("Authorization", "Bearer eyJhbGciOiJFZERTQSIsImtpZCI6IjFjZDZhOTIy...")
  req.Header.Add("Content-Type", "application/json")
  req.Header.Add("X-Idempotency-Key", "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d")

  res, _ := http.DefaultClient.Do(req)
  defer res.Body.Close()
  respBody, _ := ioutil.ReadAll(res.Body)
  fmt.Println(string(respBody))
}
import requests

response = requests.post(
  "https://api.hexpay.io/v1/payments",
  json={
    "amount": "100.00",
    "currency": "USD",
    "payment_options": {
      "methods": [{"coin": "USDT", "chain": "TON"}]
    },
    "order_id": "order-2026-00124",
    "webhookURL": "https://merchant.com/webhooks/hexpay"
  },
  headers={
    "Authorization": "Bearer eyJhbGciOiJFZERTQSIsImtpZCI6IjFjZDZhOTIy...",
    "Content-Type": "application/json",
    "X-Idempotency-Key": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
  }
)

payment = response.json()

Response — payment immediately in pending status with deposit address:

{
  "id": "019327c6-2058-7901-b234-56789abcdeff",
  "status": "pending",
  "order_id": "order-2026-00124",
  "amount": "100.00",
  "currency": "USD",
  "checkoutURL": "https://payment.hexpay.io/019327c6-2058-7901-b234-56789abcdeff",
  "paymentDetails": {
    "address": "UQBf_DO8wsBddOcMnGEOyREEHPPKMBL2F26GQFOV7FQdYY_a",
    "coinAmount": "35.782",
    "coin": {
      "name": "Tether",
      "symbol": "USDT",
      "imgUrl": "https://assets.hexpay.io/coins/usdt.svg"
    },
    "chain": {
      "name": "TON",
      "symbol": "TON",
      "imgUrl": "https://assets.hexpay.io/chains/ton.svg"
    }
  },
  "timer": {
    "createdAt": "2026-01-20T10:00:00Z",
    "expiresAt": "2026-01-20T11:00:00Z"
  }
}

You can either redirect the customer to checkoutURL (they land directly on the deposit screen) or display paymentDetails.address and paymentDetails.coinAmount in your own UI — they must send exactly that amount to that address on the TON blockchain.


Request Fields

FieldTypeRequiredDescription
amountstringYesPositive decimal, e.g. "100.00". No leading zeros on the integer part.
currencystringYesFiat code (USD, EUR, RUB) or coin ticker (TON, USDT, NOT, DOGS, BUILD, BLUM, DUST, DYOR, STON, XAUt0). Defines the unit of value, not the payment coin.
payment_options.methodsarrayNoExactly one {coin, chain} entry for Preselected mode. Omit for Customer Choice.
ttlinteger (int64)NoPayment window in seconds. Min 900, max 43200, default 3600.
order_idstringNoYour internal order ID, max 128 chars. Returned in all responses and webhooks.
descriptionstringNoHuman-readable payment purpose, max 512 chars. May be shown to the customer.
metadataobjectNoArbitrary key-value pairs (max 10 keys, string values up to 512 chars).
webhookURLstringNoHTTPS URL for lifecycle notifications. Must be publicly reachable — localhost and private network addresses are rejected.
X-Idempotency-Keystring (UUID)NoHeader. If provided, retrying with the same key within 24 hours returns the cached response without creating a duplicate payment.

Supported currency + method combinations

currencypayment_options.methodsInitial statuspaymentDetails
USD(omitted)createdabsent
TON(omitted)createdabsent
USD[{coin:"USDT",chain:"TON"}]pendingpopulated
TON[{coin:"USDT",chain:"TON"}]pendingpopulated
TON[{coin:"TON",chain:"TON"}]pendingpopulated

Tracking Payment Status

After creating a payment, poll its status to know when to fulfill the order.

For lightweight polling use GET /v1/payments/{id}/status — it returns only the status field. Once the status you care about is reached, fetch the full object with GET /v1/payments/{id}.

created  →  pending  →  completed  ✓ fulfill order
       ↘           ↘
        cancelled   expired

Configure webhookURL when creating the payment to receive a POST notification when the payment is completed — this removes the need to poll at all.

Learn about webhooks →


Next Steps