Skip to content
Last updated

Tutorial: E-commerce platform integration

What you will build

An end-to-end payment flow for an e-commerce store that:

  1. Tokenizes card data at checkout
  2. Authorizes payment when the order is placed
  3. Captures payment when the order ships
  4. Handles cancellations and refunds

Architecture

image

Prerequisites

  • A sandbox API key — see Obtain API credentials
  • A server-side application (Python, Node.js, or equivalent)
  • A database for order and payment state

Step 1: Design your payment data model

Track the relationship between orders and payments in your database.

FieldTypePurpose
order_idstringYour internal order ID
transaction_idstringParadise Gateway transaction ID
payment_tokenstringTokenized payment method
amountintegerAmount in cents
stateenumpending, authorized, captured, canceled, refunded
correlation_idstringFor support requests

Step 2: Tokenize at checkout

When the customer submits payment details, tokenize the card before doing anything else. This keeps raw card data off your systems.

import requests, os

API_KEY = os.environ["PARADISE_API_KEY"]
BASE = os.environ.get("PARADISE_BASE_URL", "https://api.dev.paradisegateway.net")
HEADERS = {"Content-Type": "application/json", "APIKEY": API_KEY}

def tokenize_card(card_data: dict, customer_id: str) -> str:
    resp = requests.post(f"{BASE}/v1/payment_tokens", headers=HEADERS, json={
        "customer_id": customer_id,
        "card": {
            "pan": card_data["pan"],
            "expiry_month": card_data["expiry_month"],
            "expiry_year": card_data["expiry_year"],
            "cvv": card_data["cvv"],
            "cardholder_name": card_data["name"],
        },
    })
    resp.raise_for_status()
    return resp.json()["token"]

Step 3: Authorize on order placement

Place a hold on the customer's card for the order amount. Do not capture yet — you'll do that when the order ships.

def authorize_payment(token: str, amount: int, order_id: str) -> dict:
    resp = requests.post(f"{BASE}/v1/transactions", headers=HEADERS, json={
        "type": "card_auth",
        "amount": amount,
        "payment_token": token,
        "order_id": order_id,
    })
    resp.raise_for_status()
    result = resp.json()

    if result["response_status"] != "approved":
        raise ValueError(f"Auth declined: {result['response_code']}")

    return {
        "transaction_id": result["id"],
        "correlation_id": result["correlation_id"],
        "state": "authorized",
    }

Step 4: Capture on shipment

When the warehouse marks the order as shipped, capture the authorized amount.

def capture_payment(transaction_id: str, amount: int | None = None) -> dict:
    payload = {}
    if amount is not None:
        payload["amount"] = amount

    resp = requests.post(
        f"{BASE}/v1/transactions/{transaction_id}/capture",
        headers=HEADERS,
        json=payload,
    )
    resp.raise_for_status()
    return resp.json()
Partial shipments

If you ship part of the order, capture only the shipped amount. See Handle partial captures.

Step 5: Handle cancellations and refunds

image

def cancel_or_refund(transaction_id: str, is_settled: bool, amount: int | None = None) -> dict:
    payload = {}
    if is_settled:
        payload["type"] = "card_refund"
        if amount:
            payload["amount"] = amount
    resp = requests.post(
        f"{BASE}/v1/transactions/{transaction_id}/cancel",
        headers=HEADERS,
        json=payload,
    )
    resp.raise_for_status()
    return resp.json()

Step 6: Synchronize payment state

Keep your order database in sync with Paradise Gateway by checking transaction state.

def sync_payment_state(transaction_id: str) -> str:
    resp = requests.get(f"{BASE}/v1/transactions/{transaction_id}", headers=HEADERS)
    resp.raise_for_status()
    return resp.json()["transaction_state"]

State mapping

Paradise Gateway stateYour order stateNext action
authorizedOrder confirmedShip or cancel
capturedPayment pending settlementWait for settlement
settledPayment completeFulfill order
canceledCanceledRestock inventory
declinedPayment failedPrompt for new card
refundedRefundedProcess return

Best practices

  • Always auth first, capture on ship — avoids charging for out-of-stock items.
  • Store transaction_id and correlation_id — you'll need them for refunds and support.
  • Use tokens for returning customers — skip tokenization on repeat purchases.
  • Implement idempotency keys — prevent duplicate charges on checkout retries.
  • Log every API interaction — see Log and monitor API errors.
  • Handle declines gracefully — see Handle declined transactions.

Next steps