Quickstart

Overview

This guide will walk you through integrating Unter payments into your application in under 15 minutes. You'll learn how to accept cryptocurrency payments with just a few API calls.

What you'll build: A simple payment flow that creates a payment request and processes the payment.

What you'll need:

  • An Unter merchant account with API keys

  • A basic understanding of REST APIs

  • A development environment (Node.js, Python, or PHP)

Step 1: Get Your API Key

  1. Log into the Unter merchant portal

  2. Navigate to Settings β†’ API Keys

  3. Create a new API key with these permissions:

    • create_payments

    • view_payments

    • manage_payments

  4. Copy your API key - it starts with unter_ and you'll only see it once

  5. Store it securely in your environment variables

# Add to your .env file
UNTER_API_KEY=unter_abc123def456ghi789...

Step 2: Explore Available Chains and Tokens

Before creating payments, discover what cryptocurrencies you can receive:

# Get all supported blockchains with their tokens
curl https://api.unter.tech/api/public/chains?include_tokens=true

This returns chains like Ethereum, Polygon, and Solana with their available tokens (USDC, ETH, USDT, etc.).

Key points:

  • No authentication required for chain/token endpoints

  • Use the numeric token_id when creating payment requests

  • Different chains support different tokens

Step 3: Create Your First Payment Request

Let's create a payment request for $10 USDC on Ethereum:

Find USDC on Ethereum

First, identify the token and chain IDs:

curl https://api.unter.tech/api/public/chains/1/tokens?stablecoins_only=true

From the response, you'll see USDC has:

  • token_id: 1 (example)

  • chain_id: 1 (Ethereum)

  • decimals: 6

Create the Payment Request

curl -X POST https://api.unter.tech/api/payment-requests \
  -H "X-API-Key: unter_YOUR_API_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": "10000000",
    "token_id": 1,
    "chain_id": 1,
    "recipient_address": "0x742C4B8C2515Ad1D8e1C71e8e24c8D5F9A1a8B5A",
    "external_id": "order_123",
    "description": "Premium subscription payment"
  }'

Understanding the amount:

  • USDC has 6 decimals

  • $10.00 = 10,000,000 (add 6 zeros)

  • Always use strings, never floats

Success Response:

{
  "data": {
    "public_id": "550e8400-e29b-41d4-a716-446655440000",
    "shortcode": "A4B2C8XZ",
    "payment_url": "https://pay.unter.tech/pay/A4B2C8XZ",
    "amount": {
      "raw": "10000000",
      "formatted": "10.00",
      "decimals": 6
    },
    "status": "active",
    "expires_at": "2024-08-15T18:00:00.000Z"
  }
}

Step 4: Handle Webhook Events

Create a webhook endpoint and configure it in your settings to receive payment notifications:

JavaScript (Express.js)

const express = require('express');
const crypto = require('crypto');

const app = express();
app.use('/webhooks', express.raw({ type: 'application/json' }));

const WEBHOOK_SECRET = process.env.UNTER_WEBHOOK_SECRET; // From merchant portal

function verifyWebhookSignature(payload, signature, secret) {
  const elements = {};
  signature.split(',').forEach(pair => {
    const [key, value] = pair.split('=');
    elements[key] = value;
  });

  if (!elements.t || !elements.v1) return false;

  const timestamp = parseInt(elements.t);
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;

  const signedPayload = `${timestamp}.${payload}`;
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(expectedSignature, 'hex'),
    Buffer.from(elements.v1, 'hex')
  );
}

app.post('/webhooks/unter', (req, res) => {
  const signature = req.headers['unter-signature'];
  const payload = req.body.toString();

  // Verify signature
  if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
    return res.status(400).send('Invalid signature');
  }

  const event = JSON.parse(payload);
  
  switch (event.type) {
    case 'payment.succeeded':
      handlePaymentSuccess(event.data.object);
      break;
    case 'payment.failed':
      handlePaymentFailure(event.data.object);
      break;
  }

  res.status(200).send('OK');
});

function handlePaymentSuccess(payment) {
  console.log('Payment succeeded:', payment.id);
  console.log('Amount:', payment.amount.formatted, payment.currency);
  console.log('Order:', payment.reference);
  
  // Update your database
  // Send confirmation email
  // Fulfill the order
}

function handlePaymentFailure(payment) {
  console.log('Payment failed:', payment.id);
  // Update order status
  // Notify customer
}

app.listen(3000);

Common Gotchas

1. Amount Format

❌ Wrong: "amount": 10.5 (number) βœ… Correct: "amount": "10500000" (string in smallest unit)

2. Token/Chain Validation

❌ Wrong: Using token_id without checking if it exists on the chain βœ… Correct: Validate token exists on specified chain first

3. Webhook Security

❌ Wrong: Processing webhooks without signature verification βœ… Correct: Always verify webhook signatures

4. Error Handling

❌ Wrong: Not handling API errors gracefully βœ… Correct: Implement proper try/catch with specific error handling

Next Steps

Now that you have a working integration:

  1. Set up proper webhook handling for production

  2. Learn about all API endpoints for advanced features

  3. Implement error handling for edge cases

  4. Add payment cancellation functionality

  5. Explore all supported chains and tokens

Last updated