Server-Side Integration

Target URL Verification

When users access your PayGate, Sigwei forwards paid requests to your target URL with authentication headers. You have two authentication modes to choose from.

Payment Headers

All proxied requests include these payment headers, regardless of authentication mode:

  • X-Payment: Base64-encoded payment authorization data (contains payer address, amount, nonce, signature, etc.)

  • X-Payment-Response: Base64-encoded settlement response from blockchain (contains transaction hash, network, success status)

These headers allow your target server to:

  • Verify the payment independently if desired

  • Track which wallet paid for the request

  • Link requests to on-chain transactions

  • Implement custom payment verification logic

When headerAuthMode is set to "hmac" (default), Sigwei adds an HMAC signature for secure authentication:

Signature Computation: HMAC-SHA256(X-Payment + "|" + X-Payment-Response, secret)

The signature proves the request came from Sigwei and includes valid payment data.

// Node.js example - HMAC verification
const crypto = require('crypto');

app.get('/api/data', (req, res) => {
  const xPayment = req.headers['x-payment'];
  const xPaymentResponse = req.headers['x-payment-response'];
  const signatureHeader = req.headers['sigwei-auth-signature'];
  const secret = process.env.SIGWEI_SECRET; // From your paygate settings

  if (!xPayment || !xPaymentResponse) {
    return res.status(401).json({ error: 'Missing payment headers' });
  }

  if (!signatureHeader) {
    return res.status(401).json({ error: 'Missing authentication signature' });
  }

  // Construct message from payment headers
  const message = xPayment + '|' + xPaymentResponse;

  // Verify HMAC signature
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('base64');

  if (signatureHeader !== expectedSignature) {
    return res.status(403).json({ error: 'Invalid signature' });
  }

  // Optional: Decode and verify payment data independently
  const paymentData = JSON.parse(Buffer.from(xPayment, 'base64').toString());
  const settlementData = JSON.parse(Buffer.from(xPaymentResponse, 'base64').toString());

  console.log('Paid by:', paymentData.payload.authorization.from);
  console.log('Transaction:', settlementData.transaction);

  res.json({ data: 'Your protected data' });
});

Plaintext Mode (Simple)

When headerAuthMode is set to "plaintext", Sigwei adds a simple secret header:

// Node.js example - Plaintext verification
app.get('/api/data', (req, res) => {
  const expectedSecret = process.env.SIGWEI_SECRET; // From your paygate settings
  if (req.headers['sigwei-secret'] !== expectedSecret) {
    return res.status(403).json({ error: 'Unauthorized' });
  }
  res.json({ data: 'Your protected data' });
});

Why Authentication Matters

Security Issue: x-payment headers can be recreated from blockchain transaction data. Anyone could theoretically access protected PayGates by reconstructing payment headers from public blockchain transactions.

Solution: Enable requireAuth: true on PayGates. This ensures only the original payer (verified by wallet signature) can access content, even if someone else copies the payment header.

Why Sigwei Secret is Crucial

The Problem: Without verification, anyone could bypass your PayGate by calling your API directly, avoiding payment entirely.

The Solution: Sigwei Secret ensures requests come from legitimate paying users via Sigwei's proxy:

  • You set the secret when creating the PayGate or generate via API

  • Every paid request includes authentication headers

  • Your backend rejects requests without valid authentication

  • Direct API access is blocked, payments are enforced

Backend Implementation

Python Example

import hmac
import hashlib
import base64
import json
import os
from flask import Flask, request, jsonify

app = Flask(__name__)

def verify_hmac_request(request):
    x_payment = request.headers.get('x-payment')
    x_payment_response = request.headers.get('x-payment-response')
    signature_header = request.headers.get('sigwei-auth-signature')
    secret = os.environ.get('SIGWEI_SECRET')

    if not x_payment or not x_payment_response:
        return False, None, None

    if not signature_header:
        return False, None, None

    # Construct message from payment headers
    message = x_payment + '|' + x_payment_response

    # Verify HMAC signature
    expected_signature = base64.b64encode(
        hmac.new(secret.encode(), message.encode(), hashlib.sha256).digest()
    ).decode()

    if signature_header != expected_signature:
        return False, None, None

    # Optional: Decode payment data for additional verification
    payment_data = json.loads(base64.b64decode(x_payment))
    settlement_data = json.loads(base64.b64decode(x_payment_response))

    return True, payment_data, settlement_data

@app.route('/api/data')
def get_data():
    verified, payment_data, settlement_data = verify_hmac_request(request)

    if not verified:
        return jsonify({'error': 'Unauthorized'}), 403

    # Optional: Log payment information
    if payment_data:
        print(f"Paid by: {payment_data['payload']['authorization']['from']}")
        print(f"Transaction: {settlement_data['transaction']}")

    return jsonify({'data': 'Your protected data'})

Managing Secrets

Get or Regenerate Secret

# Get current secret for a PayGate
curl -X GET http://localhost:8080/api/v1/paygates/123 \
     -H "Authorization: Bearer YOUR_JWT_TOKEN"

# Regenerate secret (generates new random secret)
curl -X PATCH http://localhost:8080/api/v1/paygates/123/secret \
     -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"sigweiSecret": ""}'

# Set custom secret
curl -X PATCH http://localhost:8080/api/v1/paygates/123/secret \
     -H "Authorization: Bearer YOUR_JWT_TOKEN" \
     -H "Content-Type: application/json" \
     -d '{"sigweiSecret": "your-custom-secret"}'

Request Timeouts & Size Limits

Sigwei enforces timeout and response size limits to prevent abuse and manage infrastructure costs.

Timeout Configuration

Default: 10 minutes (600 seconds)

The proxy timeout determines how long Sigwei will wait for your target URL to respond. This generous default supports:

  • AI endpoints (OpenAI, Claude, etc.)

  • Long-running computations

  • Large data processing

When requests timeout:

  • Client receives 502 Bad Gateway

  • Metrics are still captured for analytics

  • Credits are consumed (payment was made, timeout is server-side)

Best Practices:

  • Design APIs to respond within 10 minutes when possible

  • Use async patterns for longer operations (webhook callbacks)

  • Return processing IDs immediately, fetch results later

  • Consider chunking large responses

Response Size Limits

Default: 10MB (10,485,760 bytes)

Sigwei blocks responses exceeding this limit to prevent egress bandwidth abuse on hosting infrastructure.

When size limit exceeded:

  • Request blocked with 502 Bad Gateway

  • Warning logged with actual size and limit

  • Metrics captured showing blocked request

  • Credits are consumed (payment was made, size limit is protective)

Handling Large Responses:

For responses larger than 10MB, use File PayGates instead:

  • Upload files to Sigwei's storage (R2)

  • Users get presigned download URLs

  • No bandwidth cost to Sigwei (direct R2 → user)

  • Better user experience for large files

Example - Wrong way (proxy large data):

# ❌ This will hit the 10MB limit
curl -X POST https://402ify.com/api/v1/paygates \
  -H "Authorization: Bearer $JWT_TOKEN" \
  -d '{
    "targetURL": "https://api.example.com/export/csv",
    "price": 100000,
    "resourceType": "url"
  }'

Example - Right way (use file PayGate):

# ✓ Use file PayGates for large content
curl -X POST https://402ify.com/api/v1/paygates \
  -H "Authorization: Bearer $JWT_TOKEN" \
  -F "price=100000" \
  -F "resourceType=file" \
  -F "file=@large-dataset.csv"

API Design Recommendations

For API Providers:

  1. Paginate large datasets - Return data in chunks

  2. Stream processing - Use streaming responses where possible

  3. Compression - gzip/brotli compress responses

  4. Async patterns - Return job IDs for long operations

Example - Pagination:

{
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 100,
    "total": 5000,
    "nextPage": "/api/data?page=2"
  }
}

Security Best Practices

  • Store secrets securely: Use environment variables or key management systems

  • Validate every request: Check authentication headers on all protected endpoints

  • Use HMAC mode: More secure than plaintext for production environments

  • Rotate secrets regularly: Update PayGate secrets periodically via API

  • Log access attempts: Monitor for unauthorized patterns and failed authentications

  • Rate limiting: Implement rate limiting on your target URLs to prevent abuse

  • Response size awareness: Design APIs to stay under 10MB or use file PayGates for larger content

Last updated