PYMSTR
Docs

Code Examples

Complete, copy-paste ready integration examples in every language. All examples use environment variables for API keys.

Create a Payment

Create a payment and get the checkout URL.

JavaScript
// Create a payment and get the checkout URL
const PYMSTR_API_KEY = process.env.PYMSTR_API_KEY

async function createPayment(amount, currency, title, externalId) {
  const response = await fetch('https://api.pymstr.com/v1/payments', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${PYMSTR_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ amount, currency, title, externalId }),
  })

  if (!response.ok) {
    const error = await response.json()
    throw new Error(`${error.statusCode}: ${error.message}`)
  }

  return response.json()
}

// Usage
const payment = await createPayment('100.00', 'USD', 'Order #123', 'order-123')
console.log('Checkout URL:', payment.paymentUrl)

Create a Payout

Disburse to 1–100 payees in one call. Pymstr's fee is added on top — there is no top-level amount.

JavaScript
// Create a payout to multiple payees
const PYMSTR_API_KEY = process.env.PYMSTR_API_KEY

async function createPayout(payees, currency = 'USD') {
  const response = await fetch('https://api.pymstr.com/v1/payouts', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${PYMSTR_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ currency, payees }),
  })

  if (!response.ok) {
    const error = await response.json()
    throw new Error(`${error.statusCode}: ${error.message}`)
  }

  return response.json()
}

// Usage
const payout = await createPayout([
  { address: '0x1111...2222', amount: '60.00' },
  { address: '0x3333...4444', amount: '40.00' },
])
console.log('Payout URL:', payout.payoutUrl)
console.log('Total (incl. fee):', payout.amount, '— disbursed:', payout.disbursedAmount)

Create Payment + Handle Webhook

Complete flow: create a payment, set up a webhook handler, and verify the signature.

JavaScript
import express from 'express'
import { createHmac, timingSafeEqual } from 'crypto'

const app = express()
const API_KEY = process.env.PYMSTR_API_KEY
const WEBHOOK_SECRET = process.env.PYMSTR_WEBHOOK_SECRET

// 1. Create a payment
async function createPayment(orderId, amount) {
  const res = await fetch('https://api.pymstr.com/v1/payments', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      amount,
      currency: 'USD',
      externalId: orderId,
    }),
  })
  return res.json()
}

// 2. Handle webhook
app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  const sig = req.headers['x-pymstr-signature']
  const body = req.body.toString()

  // Parse signature
  const parts = sig.split(',')
  const timestamp = parts.find(p => p.startsWith('t='))?.slice(2)
  const signature = parts.find(p => p.startsWith('v1='))?.slice(3)

  // Verify timestamp (5 min tolerance)
  if (Math.abs(Date.now() / 1000 - parseInt(timestamp)) > 300) {
    return res.status(400).send('Timestamp too old')
  }

  // Verify HMAC
  const expected = createHmac('sha256', WEBHOOK_SECRET)
    .update(`${timestamp}.${body}`)
    .digest('hex')

  const sigBuf = Buffer.from(signature, 'hex')
  const expBuf = Buffer.from(expected, 'hex')

  if (sigBuf.length !== expBuf.length || !timingSafeEqual(sigBuf, expBuf)) {
    return res.status(401).send('Invalid signature')
  }

  const { event, data } = JSON.parse(body)

  if (event === 'payment.completed') {
    // 3. Fetch full payment details
    const payment = await fetch(
      `https://api.pymstr.com/v1/payments/${data.paymentId}`,
      { headers: { 'Authorization': `Bearer ${API_KEY}` } }
    ).then(r => r.json())

    console.log('Payment completed:', payment.externalId, payment.amountToken, payment.token)
    // Update your order status...
  }

  res.sendStatus(200)
})

app.listen(3000)

Get Payment Status + Cancel

Check payment status and cancel if still active.

JavaScript
const API_KEY = process.env.PYMSTR_API_KEY

async function getPayment(id) {
  const res = await fetch(`https://api.pymstr.com/v1/payments/${id}`, {
    headers: { 'Authorization': `Bearer ${API_KEY}` },
  })
  if (!res.ok) throw new Error(`${res.status}: ${res.statusText}`)
  return res.json()
}

async function cancelPayment(id) {
  const res = await fetch(`https://api.pymstr.com/v1/payments/${id}`, {
    method: 'DELETE',
    headers: { 'Authorization': `Bearer ${API_KEY}` },
  })
  if (res.status !== 204) {
    const error = await res.json()
    throw new Error(`${error.statusCode}: ${error.message}`)
  }
}

// Usage: cancel only if still active
const payment = await getPayment('01234567-89ab-cdef-0123-456789abcdef')

if (payment.status === 'ACTIVE') {
  await cancelPayment(payment.id)
  console.log('Payment cancelled')
} else {
  console.log(`Cannot cancel: status is ${payment.status}`)
}