Send Pay Links
Guides

External E-commerce Integration

Integrate Send Pay Links with your existing shopping cart or e-commerce platform

External E-commerce Integration

This guide explains how to integrate Send Pay Links with your external shopping cart, e-commerce platform, or custom application to generate checkout pages on-the-fly with dynamic cart data.

Overview

Send Pay Links acts as a headless checkout system. Your e-commerce store calculates the cart totals, then sends the data to our API to generate a hosted checkout page.

┌─────────────────┐     ┌──────────────────┐     ┌─────────────────┐
│  Your Store     │     │  Send Pay Links  │     │  Checkout Page  │
│  (Cart System)  │────▶│  API             │────▶│  /c/[code]      │
└─────────────────┘     └──────────────────┘     └─────────────────┘
        │                        │                        │
        │  POST cart data        │                        │
        │───────────────────────▶│                        │
        │                        │                        │
        │  { checkoutUrl }       │                        │
        │◀───────────────────────│                        │
        │                        │                        │
        │  Redirect customer ─────────────────────────────▶

Step 1: Generate a Checkout URL

From your backend, POST your cart data to generate a checkout URL:

POST https://sendpaylinks.com/api/token/generate
Content-Type: application/json

Request Body

{
  "orderId": "cart_12345",
  "merchantId": "your_store_id",
  
  "customer": {
    "email": "customer@example.com",
    "firstName": "John",
    "lastName": "Doe",
    "phone": "+1234567890"
  },
  
  "shippingAddress": {
    "line1": "123 Main St",
    "line2": "Apt 4B",
    "city": "New York",
    "state": "NY",
    "postalCode": "10001",
    "country": "US"
  },
  
  "lineItems": [
    {
      "id": "prod_abc",
      "name": "Blue Widget",
      "quantity": 2,
      "unitPrice": 2999,
      "sku": "WIDGET-BLUE",
      "imageUrl": "https://yourstore.com/images/widget.jpg"
    },
    {
      "id": "prod_xyz",
      "name": "Red Gadget",
      "quantity": 1,
      "unitPrice": 4999,
      "sku": "GADGET-RED"
    }
  ],
  
  "subtotal": 10997,
  "shipping": 999,
  "tax": 880,
  "discount": 0,
  "total": 12876,
  "currency": "USD",
  
  "allowedProviders": ["stripe", "nmi"],
  "successUrl": "https://yourstore.com/order-confirmed",
  "cancelUrl": "https://yourstore.com/cart",
  "webhookUrl": "https://yourstore.com/api/webhooks/checkout"
}

Response

{
  "success": true,
  "code": "abc123xyz",
  "checkoutUrl": "https://sendpaylinks.com/c/abc123xyz",
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "payload": { ... }
}

Redirect the Customer

After receiving the response, redirect your customer to the checkoutUrl:

// JavaScript
window.location.href = response.checkoutUrl;
// PHP
header("Location: " . $response['checkoutUrl']);
exit;
# Python/Flask
return redirect(response['checkoutUrl'])

Step 2: Understanding Key Fields

Required Fields

FieldTypeDescription
orderIdstringYour unique order/cart identifier
merchantIdstringYour store identifier (for tracking)
customerobjectCustomer contact information
shippingAddressobjectShipping address
lineItemsarrayProducts in the cart
totalnumberTotal amount in cents (e.g., 9999 = $99.99)
currencystringISO currency code (e.g., "USD")
allowedProvidersarrayPayment providers to offer
successUrlstringRedirect URL after successful payment
cancelUrlstringRedirect URL if customer cancels

Optional Fields

FieldTypeDescription
webhookUrlstringURL to receive payment notifications
metadataobjectCustom key-value data passed through
metadata.brandIdstringBrand ID for multi-tenant settings
upsellConfigobjectConfigure post-purchase upsells
salesAttributionobjectTrack sales commissions

Step 3: Using merchantId vs brandId

These are two separate identifiers with different purposes:

FieldPurposeWhere It Comes From
merchantIdYour tracking identifierYou provide it (store ID, account ID, etc.)
brandIdPlatform settings identifierCreated in Send Pay Links admin

When to Use Each

merchantId - Always include this. Use your own store/account ID for:

  • Tracking orders by store
  • Analytics and reporting
  • Webhook identification

brandId - Include in metadata when you need:

  • Brand-specific payment credentials (different Stripe keys per brand)
  • Custom checkout themes
  • Organization-level settings
{
  "merchantId": "my-shopify-store",
  "metadata": {
    "brandId": "brand_abc123"
  }
}

Step 4: Receive Webhooks

Configure webhookUrl to receive real-time notifications when payments complete:

{
  "webhookUrl": "https://yourstore.com/api/webhooks/sendpaylinks"
}

Webhook Payload

{
  "type": "checkout.completed",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "object": {
      "order_id": "cart_12345",
      "transaction_id": "pi_abc123",
      "provider": "stripe",
      "amount": 12876,
      "currency": "USD",
      "status": "completed",
      "customer": {
        "email": "customer@example.com",
        "first_name": "John",
        "last_name": "Doe"
      },
      "line_items": [
        {
          "id": "prod_abc",
          "name": "Blue Widget",
          "quantity": 2,
          "unit_price": 2999,
          "total_price": 5998
        }
      ]
    }
  }
}

Code Examples

Node.js / Express

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

app.post('/checkout', async (req, res) => {
  const { cart, customer } = req.body;

  const response = await fetch('https://checkout.yoursite.com/api/token/generate', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      orderId: cart.id,
      merchantId: process.env.STORE_ID,
      customer: {
        email: customer.email,
        firstName: customer.firstName,
        lastName: customer.lastName,
      },
      lineItems: cart.items.map(item => ({
        id: item.productId,
        name: item.name,
        quantity: item.quantity,
        unitPrice: Math.round(item.price * 100), // Convert to cents
      })),
      subtotal: Math.round(cart.subtotal * 100),
      shipping: Math.round(cart.shipping * 100),
      tax: Math.round(cart.tax * 100),
      total: Math.round(cart.total * 100),
      currency: 'USD',
      allowedProviders: ['stripe'],
      successUrl: `${process.env.STORE_URL}/order-confirmed`,
      cancelUrl: `${process.env.STORE_URL}/cart`,
      webhookUrl: `${process.env.STORE_URL}/api/webhooks/checkout`,
    }),
  });

  const data = await response.json();
  res.redirect(data.checkoutUrl);
});

PHP

<?php
function createCheckout($cart, $customer) {
    $payload = [
        'orderId' => $cart['id'],
        'merchantId' => getenv('STORE_ID'),
        'customer' => [
            'email' => $customer['email'],
            'firstName' => $customer['first_name'],
            'lastName' => $customer['last_name'],
        ],
        'lineItems' => array_map(function($item) {
            return [
                'id' => $item['product_id'],
                'name' => $item['name'],
                'quantity' => $item['quantity'],
                'unitPrice' => (int)($item['price'] * 100),
            ];
        }, $cart['items']),
        'total' => (int)($cart['total'] * 100),
        'currency' => 'USD',
        'allowedProviders' => ['stripe'],
        'successUrl' => 'https://yourstore.com/order-confirmed',
        'cancelUrl' => 'https://yourstore.com/cart',
    ];

    $ch = curl_init('https://checkout.yoursite.com/api/token/generate');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $response = json_decode(curl_exec($ch), true);
    curl_close($ch);

    return $response['checkoutUrl'];
}

// Usage
header("Location: " . createCheckout($cart, $customer));
exit;
?>

Python

import requests
import os

def create_checkout(cart, customer):
    payload = {
        "orderId": cart["id"],
        "merchantId": os.environ["STORE_ID"],
        "customer": {
            "email": customer["email"],
            "firstName": customer["first_name"],
            "lastName": customer["last_name"],
        },
        "lineItems": [
            {
                "id": item["product_id"],
                "name": item["name"],
                "quantity": item["quantity"],
                "unitPrice": int(item["price"] * 100),
            }
            for item in cart["items"]
        ],
        "total": int(cart["total"] * 100),
        "currency": "USD",
        "allowedProviders": ["stripe"],
        "successUrl": "https://yourstore.com/order-confirmed",
        "cancelUrl": "https://yourstore.com/cart",
    }

    response = requests.post(
        "https://checkout.yoursite.com/api/token/generate",
        json=payload
    )

    return response.json()["checkoutUrl"]

# Usage with Flask
from flask import redirect

@app.route("/checkout", methods=["POST"])
def checkout():
    checkout_url = create_checkout(cart, customer)
    return redirect(checkout_url)

Adding Upsells

Include upsellConfig to show post-purchase offers:

{
  "orderId": "cart_12345",
  "merchantId": "your_store",
  ...
  "upsellConfig": {
    "enabled": true,
    "offers": [
      {
        "id": "upsell_premium",
        "productId": "prod_premium",
        "name": "Upgrade to Premium",
        "description": "Get 50% more features!",
        "price": 1999,
        "originalPrice": 3999,
        "ctaText": "Yes, Upgrade Me!",
        "declineText": "No Thanks"
      }
    ]
  }
}

Or reference a pre-built flow from the admin:

{
  "upsellConfig": {
    "enabled": true,
    "flowId": "flow_abc123"
  }
}

Next Steps

On this page