Checkout & Payments
Cart-based checkout with payment intents, POS terminal integration, and automatic tax calculation.
Overview
The checkout flow starts with a cart. Customers add items, then convert the cart into a checkout session that calculates tax, applies discounts, and collects payment. For in-person sales, payment intents handle the charge-and-capture flow through Dejavoo terminals.
Once payment is captured, an order is created automatically. From there you can issue refunds, void unpaid orders, or recover abandoned carts with automated emails.
Create a Cart
Start by creating a cart, then add items to it. Each item references a product and quantity. The cart tracks line items, subtotals, and is the entry point for checkout.
const whale = new WhaleClient("wk_live_...");
// Create an empty cart
const cart = await whale.cart.create();
// => { "id": "cart_a1b2c3d4-...", "items": [], "subtotal": 0 }
// Add items
await whale.cart.addItem(cart.id, {
product_id: "prod_001",
variant_id: "var_001",
quantity: 2
});
await whale.cart.addItem(cart.id, {
product_id: "prod_007",
variant_id: "var_012",
quantity: 1
});
// Fetch the updated cart
const updated = await whale.cart.get(cart.id);
// Response
{
"id": "cart_a1b2c3d4-...",
"items": [
{
"id": "ci_001",
"product_id": "prod_001",
"variant_id": "var_001",
"name": "Ceramic Mug — Ocean Blue",
"quantity": 2,
"unit_price": 24.00,
"total": 48.00
},
{
"id": "ci_002",
"product_id": "prod_007",
"variant_id": "var_012",
"name": "Linen Tote — Natural",
"quantity": 1,
"unit_price": 36.00,
"total": 36.00
}
],
"subtotal": 84.00
}Process Checkout
Convert a cart into a checkout session. Provide the customer, shipping address, and enable automatic tax calculation. The session calculates shipping, tax, and totals, then processes payment and creates the order.
const checkout = await whale.checkout.create({
cart_id: "cart_a1b2c3d4-...",
customer_id: "cust_8a3b4c5d-e6f7-8901-abcd-ef2345678901",
shipping_address: {
line1: "123 Main St",
city: "Portland",
state: "OR",
postal_code: "97201",
country: "US"
},
shipping_method: "standard",
auto_tax: true
});
// Response
{
"object": "checkout_session",
"id": "cs_9f8e7d6c-...",
"status": "complete",
"cart_id": "cart_a1b2c3d4-...",
"customer_id": "cust_8a3b4c5d-e6f7-8901-abcd-ef2345678901",
"subtotal": 84.00,
"shipping": 5.99,
"tax": 9.24,
"total": 99.23,
"tax_breakdown": [
{ "jurisdiction": "Oregon", "rate": 0.0, "amount": 0.0 },
{ "jurisdiction": "Portland", "rate": 0.11, "amount": 9.24 }
],
"order_id": "ord_7a2b3c4d-e5f6-7890-abcd-ef1234567890",
"created_at": "2026-03-10T09:00:00.000Z"
}Payment Intents (POS Terminal)
For in-person sales, create a payment intent to authorize a charge, then capture it after the terminal confirms. This two-step flow lets you validate the amount before finalizing the transaction.
// Step 1: Create a payment intent
const intent = await whale.checkout.intents.create({
amount: 99.23,
currency: "usd",
payment_method: "terminal",
metadata: {
order_id: "ord_7a2b3c4d-...",
terminal_id: "term_001"
}
});
// Response
{
"object": "payment_intent",
"id": "pi_5e4d3c2b-...",
"amount": 99.23,
"currency": "usd",
"status": "requires_capture",
"payment_method": "terminal",
"created_at": "2026-03-10T09:05:00.000Z"
}
// Step 2: Capture after terminal confirms
const captured = await whale.checkout.intents.capture("pi_5e4d3c2b-...");
// Response
{
"object": "payment_intent",
"id": "pi_5e4d3c2b-...",
"amount": 99.23,
"status": "captured",
"captured_at": "2026-03-10T09:05:12.000Z"
}Terminal Integration
WhaleTools integrates with Dejavoo payment terminals for in-store card processing. The terminal handles card reading and PIN entry while the API manages the payment lifecycle. You can abort a pending charge or cancel a completed intent before capture.
// Send a charge to the Dejavoo terminal
const charge = await whale.terminal.charge({
terminal_id: "term_001",
amount: 99.23,
currency: "usd",
payment_intent_id: "pi_5e4d3c2b-..."
});
// Response
{
"object": "terminal_charge",
"id": "tc_1a2b3c4d-...",
"terminal_id": "term_001",
"status": "processing",
"amount": 99.23
}
// Abort a charge in progress (customer walks away)
await whale.terminal.abort("tc_1a2b3c4d-...");
// Cancel an uncaptured payment intent
await whale.checkout.intents.cancel("pi_5e4d3c2b-...");
// Response
{
"object": "payment_intent",
"id": "pi_5e4d3c2b-...",
"status": "canceled",
"canceled_at": "2026-03-10T09:06:00.000Z"
}Refunds & Voids
Issue a partial or full refund on a paid order, or void an unpaid order entirely. Refunds restore inventory automatically. Voiding cancels the order and releases any held inventory.
// Partial refund
const refund = await whale.orders.refund(
"ord_7a2b3c4d-e5f6-7890-abcd-ef1234567890",
{
amount: 24.00,
reason: "Customer received damaged item",
line_items: [
{ line_item_id: "li_001", quantity: 1 }
]
}
);
// Response
{
"object": "refund",
"id": "ref_9b8c7d6e-...",
"order_id": "ord_7a2b3c4d-...",
"amount": 24.00,
"reason": "Customer received damaged item",
"status": "processed",
"inventory_restored": true,
"created_at": "2026-03-10T14:30:00.000Z"
}
// Void an unpaid order
await whale.orders.void("ord_7a2b3c4d-e5f6-7890-abcd-ef1234567890");
// Response
{
"object": "order",
"id": "ord_7a2b3c4d-...",
"status": "voided",
"voided_at": "2026-03-10T14:35:00.000Z"
}Abandoned Cart Recovery
Carts that are not converted into orders within a configurable window are marked as abandoned. List abandoned carts to see what customers left behind, then trigger a recovery email with a direct link back to their cart.
// List abandoned carts
const abandoned = await whale.abandonedCarts.list({
abandoned_after: "2026-03-07T00:00:00Z",
recovered: false,
limit: 25
});
// Response
{
"object": "list",
"data": [
{
"id": "cart_x9y8z7w6-...",
"customer": {
"id": "cust_abc123",
"name": "Alex Kim",
"email": "alex@example.com"
},
"items": 3,
"subtotal": 142.00,
"abandoned_at": "2026-03-08T16:45:00.000Z",
"recovery_email_sent": false
}
],
"total": 12
}
// Send recovery email
await whale.abandonedCarts.recover("cart_x9y8z7w6-...");
// Response
{
"object": "abandoned_cart",
"id": "cart_x9y8z7w6-...",
"recovery_email_sent": true,
"recovery_email_sent_at": "2026-03-10T10:00:00.000Z"
}API Reference
| Method | Path | Description |
|---|---|---|
| POST | /v1/stores/{store_id}/carts | Create a new cart. |
| GET | /v1/stores/{store_id}/carts/{id} | Get cart with items and totals. |
| POST | /v1/stores/{store_id}/carts/{id}/items | Add an item to a cart. |
| PATCH | /v1/stores/{store_id}/carts/{id}/items/{item_id} | Update item quantity in a cart. |
| DELETE | /v1/stores/{store_id}/carts/{id}/items/{item_id} | Remove an item from a cart. |
| POST | /v1/stores/{store_id}/checkout | Create a checkout session from a cart. |
| GET | /v1/stores/{store_id}/checkout/{id} | Get checkout session status. |
| POST | /v1/stores/{store_id}/payment-intents | Create a payment intent for terminal or card. |
| POST | /v1/stores/{store_id}/payment-intents/{id}/capture | Capture an authorized payment intent. |
| POST | /v1/stores/{store_id}/payment-intents/{id}/cancel | Cancel an uncaptured payment intent. |
| POST | /v1/stores/{store_id}/orders/{id}/refund | Issue a full or partial refund. |
| POST | /v1/stores/{store_id}/orders/{id}/void | Void an unpaid or pending order. |
| GET | /v1/stores/{store_id}/abandoned-carts | List abandoned carts with recovery status. |
| POST | /v1/stores/{store_id}/abandoned-carts/{id}/recover | Send recovery email for an abandoned cart. |