Skip to Content

Create Checkout

Create a new checkout link for a customer to complete payment.

POST /v1/checkout

Authentication

This endpoint requires API Key + RFC 9421 Signature.

HeaderRequiredDescription
blox-api-keyYesYour API key
Content-TypeYesapplication/json
Content-DigestYesSHA-256 hash of request body
Signature-InputYesRFC 9421 signature parameters
SignatureYesRFC 9421 cryptographic signature

Learn how to sign requests →


Request Body

FieldTypeRequiredDescription
addressTostringYesYour wallet address to receive payment (Ethereum or Solana format)
amountintegerYesPayment amount in cents (e.g., 15000 = 150.00 MYR)
tokenIdstring (UUID)YesThe token ID to receive payment in
redirectUrlstring (URL)YesURL to redirect customer after payment
titlestringYesPayment title displayed to customer (1–100 characters)
webhookUrlstring (URL)NoURL to receive payment status webhooks
descriptionstringNoAdditional payment details (max 500 characters)

Amount Limits

LimitValue
Minimum1,000 cents (10.00 MYR)
Maximum100,000,000 cents (1,000,000.00 MYR)

Address Formats

The addressTo field accepts:

  • Ethereum/Arbitrum: 0x followed by 40 hex characters (e.g., 0x742d35Cc6634C0532925a3b844Bc9e7595f8bD21)
  • Solana: Base58-encoded public key (e.g., DRpbCBMxVnDK7maPM5tGv6MvB3v1sRMC86PZ8okm21hy)

Example Request

curl -X POST "https://api.blox.my/v1/checkout" \ -H "blox-api-key: $BLOX_API_KEY" \ -H "Content-Type: application/json" \ -H "Content-Digest: sha-256=:X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=:" \ -H "Signature-Input: sig1=(@method @path content-digest content-type);created=1704067200;keyid=\"your_key_id\";alg=\"ed25519\"" \ -H "Signature: sig1=:MEUCIQDXy2IGhh...=:" \ -d '{ "addressTo": "0x742d35Cc6634C0532925a3b844Bc9e7595f8bD21", "amount": 15000, "tokenId": "550e8400-e29b-41d4-a716-446655440000", "redirectUrl": "https://yoursite.com/order/123/complete", "webhookUrl": "https://yoursite.com/webhooks/blox", "title": "Order #123", "description": "Premium subscription - 1 month" }'

Response

Success (201 Created)

{ "checkoutId": "8f14e45f-ceea-467f-a830-5e3e3c7e2b8a", "checkoutUrl": "https://checkout.blox.my/8f14e45f-ceea-467f-a830-5e3e3c7e2b8a", "expiresAt": "2026-02-03T15:20:00.000Z" }
FieldTypeDescription
checkoutIdstring (UUID)Unique identifier for this checkout
checkoutUrlstring (URL)The payment link to send to your customer
expiresAtstring (ISO 8601)When the checkout link expires

Important: Checkout links expire 20 minutes after creation. If the customer doesn’t complete payment within this window, the checkout is automatically cancelled.


Errors

400 Bad Request

Invalid request parameters:

{ "error": { "code": "invalid_request", "message": "Invalid token ID" } }

Common causes:

  • Invalid addressTo format
  • amount outside valid range (1,000–100,000,000)
  • Invalid tokenId UUID
  • title exceeds 100 characters
  • description exceeds 500 characters
  • Invalid URL format for redirectUrl or webhookUrl

401 Unauthorized

Authentication failed:

{ "error": { "code": "unauthorized", "message": "Invalid signature" } }

Common causes:

  • Missing or invalid blox-api-key
  • Invalid signature construction
  • Signature-Input format incorrect

403 Forbidden

Feature not enabled:

{ "error": { "code": "forbidden", "message": "Checkout feature not enabled" } }

Contact BLOX support to enable the Checkout feature for your account.


Code Examples

Node.js

import crypto from "crypto"; import canonicalize from "canonicalize"; async function createCheckout( apiKey: string, privateKey: crypto.KeyObject, checkout: { addressTo: string; amount: number; tokenId: string; redirectUrl: string; title: string; webhookUrl?: string; description?: string; } ) { const body = checkout; const canonicalBody = canonicalize(body)!; // Generate Content-Digest const bodyHash = crypto.createHash("sha256").update(canonicalBody).digest("base64"); const contentDigest = `sha-256=:${bodyHash}:`; // Generate signature const created = Math.floor(Date.now() / 1000); const keyId = apiKey.substring(0, 20); // First 20 chars as keyid const signatureParams = `(@method @path content-digest content-type);created=${created};keyid="${keyId}";alg="ed25519"`; const signatureBase = [ `"@method": POST`, `"@path": /v1/checkout`, `"content-digest": ${contentDigest}`, `"content-type": application/json`, `"@signature-params": ${signatureParams}`, ].join("\n"); const sig = crypto.sign(null, Buffer.from(signatureBase), privateKey); const signature = `sig1=:${sig.toString("base64")}:`; const response = await fetch("https://api.blox.my/v1/checkout", { method: "POST", headers: { "blox-api-key": apiKey, "Content-Type": "application/json", "Content-Digest": contentDigest, "Signature-Input": `sig1=${signatureParams}`, "Signature": signature, }, body: JSON.stringify(body), }); return response.json(); } // Usage const result = await createCheckout( process.env.BLOX_API_KEY!, privateKey, { addressTo: "0x742d35Cc6634C0532925a3b844Bc9e7595f8bD21", amount: 15000, // 150.00 MYR tokenId: "550e8400-e29b-41d4-a716-446655440000", redirectUrl: "https://yoursite.com/success", title: "Order #123", } ); console.log("Checkout URL:", result.checkoutUrl);

Python

import requests import hashlib import base64 import time import json from cryptography.hazmat.primitives import serialization def create_checkout(api_key: str, private_key_path: str, checkout: dict): # Canonicalize body def canonicalize(obj): if isinstance(obj, dict): return "{" + ",".join(f'"{k}":{canonicalize(v)}' for k, v in sorted(obj.items())) + "}" elif isinstance(obj, list): return "[" + ",".join(canonicalize(x) for x in obj) + "]" return json.dumps(obj, separators=(",", ":")) canonical_body = canonicalize(checkout) # Generate Content-Digest body_hash = base64.b64encode(hashlib.sha256(canonical_body.encode()).digest()).decode() content_digest = f"sha-256=:{body_hash}:" # Generate signature created = int(time.time()) key_id = api_key[:20] signature_params = f'(@method @path content-digest content-type);created={created};keyid="{key_id}";alg="ed25519"' signature_base = "\n".join([ '"@method": POST', '"@path": /v1/checkout', f'"content-digest": {content_digest}', '"content-type": application/json', f'"@signature-params": {signature_params}', ]) # Load private key and sign with open(private_key_path, "rb") as f: private_key = serialization.load_pem_private_key(f.read(), password=None) sig = private_key.sign(signature_base.encode()) signature = f"sig1=:{base64.b64encode(sig).decode()}:" response = requests.post( "https://api.blox.my/v1/checkout", headers={ "blox-api-key": api_key, "Content-Type": "application/json", "Content-Digest": content_digest, "Signature-Input": f"sig1={signature_params}", "Signature": signature, }, data=json.dumps(checkout, separators=(",", ":")), ) return response.json() # Usage result = create_checkout( api_key="your_api_key", private_key_path="./private_key.pem", checkout={ "addressTo": "0x742d35Cc6634C0532925a3b844Bc9e7595f8bD21", "amount": 15000, "tokenId": "550e8400-e29b-41d4-a716-446655440000", "redirectUrl": "https://yoursite.com/success", "title": "Order #123", } ) print("Checkout URL:", result["checkoutUrl"])

Next Steps

After creating a checkout:

  1. Send the link — Share checkoutUrl with your customer via email, SMS, or in-app
  2. Monitor statusQuery checkout status or wait for webhook
  3. Handle webhookProcess payment notifications
Last updated