An end-to-end payment flow for an e-commerce store that:
- Tokenizes card data at checkout
- Authorizes payment when the order is placed
- Captures payment when the order ships
- Handles cancellations and refunds

- A sandbox API key — see Obtain API credentials
- A server-side application (Python, Node.js, or equivalent)
- A database for order and payment state
Track the relationship between orders and payments in your database.
| Field | Type | Purpose |
|---|---|---|
order_id | string | Your internal order ID |
transaction_id | string | Paradise Gateway transaction ID |
payment_token | string | Tokenized payment method |
amount | integer | Amount in cents |
state | enum | pending, authorized, captured, canceled, refunded |
correlation_id | string | For support requests |
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"]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",
}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.

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()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"]| Paradise Gateway state | Your order state | Next action |
|---|---|---|
authorized | Order confirmed | Ship or cancel |
captured | Payment pending settlement | Wait for settlement |
settled | Payment complete | Fulfill order |
canceled | Canceled | Restock inventory |
declined | Payment failed | Prompt for new card |
refunded | Refunded | Process return |
- Always auth first, capture on ship — avoids charging for out-of-stock items.
- Store
transaction_idandcorrelation_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.