Skip to main content

Sales Block

Sales Block

Complete commerce infrastructure for subscriptions and payments

The Sales Block provides everything you need to monetize your application - from shopping carts and one-time purchases to subscription billing and payment processing. Integrated with Stripe out of the box.

Features​

  • Shopping Carts - Persistent carts with line items, discounts, taxes, and inventory validation
  • Order Management - Complete order lifecycle from creation to fulfillment
  • Subscriptions - Recurring billing with plans, trials, upgrades, and usage-based pricing
  • Payment Processing - Secure payments with Stripe, multiple methods, automatic retries
  • Invoicing - Automated invoice generation, PDF export, payment reminders
  • Checkout Flow - Customizable checkout with guest support, addresses, and tax calculation

API Endpoint​

ServiceURL
Saleshttps://sales.api.us.23blocks.com

Environment Routing: One URL, one environment. All shared-platform API keys are live keys:

  • pk_live_* / sk_live_* → your production tenant. Need a separate staging environment? It is available as a paid add-on on deployments in your own cloud account — see 23blocks in a Box.

Quick Start​

Installation​

npm install @23blocks/sdk

Initialize the Client​

import { create23BlocksClient } from '@23blocks/sdk';

const client = create23BlocksClient({
urls: { sales: 'https://sales.api.us.23blocks.com' },
apiKey: 'your-api-key', // Your live API key (pk_live_*)
});

Create a Shopping Cart​

// Create a new cart
const cart = await client.sales.createCart({
userId: 'user-123',
currency: 'USD'
});

// Add items to cart
await client.sales.addCartItem(cart.id, {
productId: 'prod-abc',
quantity: 2,
unitPrice: 29.99
});

// Apply a discount
await client.sales.applyDiscount(cart.id, {
code: 'SAVE20'
});

Create a Subscription​

const subscription = await client.sales.createSubscription({
userId: 'user-123',
planId: 'pro-monthly',
paymentMethodId: 'pm_xxx',
trialDays: 14
});

Authentication​

All Sales Block endpoints require authentication via API key and App ID headers:

X-App-Id: your-app-id
X-Api-Key: your-api-key
Content-Type: application/json

User-scoped operations also require user authentication:

Authorization: Bearer <user-token>

Shopping Carts​

Shopping carts manage the customer's items before checkout, handling inventory validation, pricing, taxes, and discounts.

Cart Object​

{
"data": {
"id": "cart-uuid",
"type": "carts",
"attributes": {
"user_id": "user-123",
"status": "active",
"currency": "USD",
"subtotal": 89.97,
"discount_amount": 17.99,
"tax_amount": 5.76,
"total": 77.74,
"item_count": 3,
"metadata": {},
"expires_at": "2026-01-09T12:00:00Z",
"created_at": "2026-01-02T12:00:00Z",
"updated_at": "2026-01-02T12:30:00Z"
},
"relationships": {
"items": {
"data": [
{ "type": "cart_items", "id": "item-1" },
{ "type": "cart_items", "id": "item-2" }
]
},
"discount": {
"data": { "type": "discounts", "id": "discount-1" }
}
}
}
}

Create Cart​

POST /api/v1/sales/carts

Request Body:

{
"data": {
"type": "carts",
"attributes": {
"user_id": "user-123",
"currency": "USD",
"metadata": {
"source": "web",
"campaign": "summer-sale"
}
}
}
}

Response: 201 Created

Get Cart​

GET /api/v1/sales/carts/:cart_id

Query Parameters:

ParameterTypeDescription
includestringInclude related resources: items, discount, user

Response: 200 OK with cart object

Update Cart​

PATCH /api/v1/sales/carts/:cart_id

Request Body:

{
"data": {
"type": "carts",
"attributes": {
"currency": "EUR",
"metadata": {
"notes": "Gift order"
}
}
}
}

Delete Cart​

DELETE /api/v1/sales/carts/:cart_id

Response: 204 No Content

List User Carts​

GET /api/v1/sales/users/:user_id/carts

Query Parameters:

ParameterTypeDescription
statusstringFilter by status: active, converted, abandoned, expired
page[number]integerPage number (default: 1)
page[size]integerItems per page (default: 20, max: 100)

Cart Items​

Cart Item Object​

{
"data": {
"id": "item-uuid",
"type": "cart_items",
"attributes": {
"cart_id": "cart-123",
"product_id": "prod-abc",
"product_name": "Pro Subscription",
"quantity": 1,
"unit_price": 29.99,
"subtotal": 29.99,
"metadata": {},
"created_at": "2026-01-02T12:00:00Z"
}
}
}

Add Item to Cart​

POST /api/v1/sales/carts/:cart_id/items

Request Body:

{
"data": {
"type": "cart_items",
"attributes": {
"product_id": "prod-abc",
"quantity": 2,
"unit_price": 29.99,
"metadata": {
"variant": "blue",
"size": "large"
}
}
}
}

Response: 201 Created

Update Cart Item​

PATCH /api/v1/sales/carts/:cart_id/items/:item_id

Request Body:

{
"data": {
"type": "cart_items",
"attributes": {
"quantity": 3
}
}
}

Remove Cart Item​

DELETE /api/v1/sales/carts/:cart_id/items/:item_id

Response: 204 No Content

Apply Discount to Cart​

POST /api/v1/sales/carts/:cart_id/apply-discount

Request Body:

{
"code": "SUMMER20"
}

Response: 200 OK with updated cart

Remove Discount from Cart​

DELETE /api/v1/sales/carts/:cart_id/discount

Response: 204 No Content


Orders​

Orders represent completed purchases with full lifecycle management.

Order Object​

{
"data": {
"id": "order-uuid",
"type": "orders",
"attributes": {
"order_number": "ORD-2026-00001",
"user_id": "user-123",
"status": "confirmed",
"fulfillment_status": "pending",
"payment_status": "paid",
"currency": "USD",
"subtotal": 89.97,
"discount_amount": 17.99,
"shipping_amount": 9.99,
"tax_amount": 5.76,
"total": 87.73,
"billing_address": {
"name": "John Doe",
"line1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "US"
},
"shipping_address": {
"name": "John Doe",
"line1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "US"
},
"metadata": {},
"notes": "Leave at door",
"created_at": "2026-01-02T12:00:00Z",
"updated_at": "2026-01-02T12:00:00Z"
},
"relationships": {
"line_items": {
"data": [
{ "type": "order_items", "id": "item-1" }
]
},
"payment": {
"data": { "type": "payments", "id": "pay-1" }
},
"invoice": {
"data": { "type": "invoices", "id": "inv-1" }
}
}
}
}

Order Statuses​

StatusDescription
pendingOrder created, awaiting payment
confirmedPayment received, order confirmed
processingOrder is being processed
shippedOrder has been shipped
deliveredOrder delivered to customer
cancelledOrder was cancelled
refundedOrder was refunded

Create Order​

POST /api/v1/sales/orders

Request Body:

{
"data": {
"type": "orders",
"attributes": {
"user_id": "user-123",
"cart_id": "cart-456",
"payment_method_id": "pm_xxx",
"billing_address": {
"name": "John Doe",
"line1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "US"
},
"shipping_address": {
"name": "John Doe",
"line1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "US"
},
"notes": "Leave at door"
}
}
}

Response: 201 Created

Get Order​

GET /api/v1/sales/orders/:order_id

Query Parameters:

ParameterTypeDescription
includestringInclude: line_items, payment, invoice, user

List Orders​

GET /api/v1/sales/orders

Query Parameters:

ParameterTypeDescription
filter[user_id]stringFilter by user ID
filter[status]stringFilter by status
filter[payment_status]stringFilter: pending, paid, failed, refunded
filter[fulfillment_status]stringFilter: pending, processing, shipped, delivered
filter[created_after]datetimeOrders created after date
filter[created_before]datetimeOrders created before date
sortstringSort by: created_at, -created_at, total, -total
page[number]integerPage number
page[size]integerItems per page

Update Order Status​

PATCH /api/v1/sales/orders/:order_id/status

Request Body:

{
"status": "shipped",
"tracking_number": "1Z999AA10123456784",
"carrier": "UPS"
}

Cancel Order​

POST /api/v1/sales/orders/:order_id/cancel

Request Body:

{
"reason": "Customer requested cancellation"
}

Subscriptions​

Manage recurring billing with flexible subscription plans.

Subscription Object​

{
"data": {
"id": "sub-uuid",
"type": "subscriptions",
"attributes": {
"user_id": "user-123",
"plan_id": "plan-pro",
"status": "active",
"current_period_start": "2026-01-02T00:00:00Z",
"current_period_end": "2026-02-02T00:00:00Z",
"trial_start": "2025-12-19T00:00:00Z",
"trial_end": "2026-01-02T00:00:00Z",
"cancel_at_period_end": false,
"cancelled_at": null,
"ended_at": null,
"quantity": 1,
"metadata": {},
"created_at": "2025-12-19T12:00:00Z",
"updated_at": "2026-01-02T12:00:00Z"
},
"relationships": {
"plan": {
"data": { "type": "plans", "id": "plan-pro" }
},
"payment_method": {
"data": { "type": "payment_methods", "id": "pm-1" }
}
}
}
}

Subscription Statuses​

StatusDescription
trialingSubscription is in trial period
activeSubscription is active and billing
past_duePayment failed, retrying
pausedSubscription temporarily paused
cancelledSubscription cancelled
unpaidPayment failed after all retries

Create Subscription​

POST /api/v1/sales/subscriptions

Request Body:

{
"data": {
"type": "subscriptions",
"attributes": {
"user_id": "user-123",
"plan_id": "plan-pro",
"payment_method_id": "pm_xxx",
"trial_days": 14,
"quantity": 5,
"metadata": {
"team_name": "Engineering"
}
}
}
}

Response: 201 Created

Get Subscription​

GET /api/v1/sales/subscriptions/:subscription_id

Query Parameters:

ParameterTypeDescription
includestringInclude: plan, payment_method, invoices, user

List Subscriptions​

GET /api/v1/sales/subscriptions

Query Parameters:

ParameterTypeDescription
filter[user_id]stringFilter by user
filter[plan_id]stringFilter by plan
filter[status]stringFilter by status
page[number]integerPage number
page[size]integerItems per page

Update Subscription​

PATCH /api/v1/sales/subscriptions/:subscription_id

Request Body:

{
"data": {
"type": "subscriptions",
"attributes": {
"plan_id": "plan-enterprise",
"quantity": 10,
"proration_behavior": "create_prorations"
}
}
}

Proration Behaviors:

ValueDescription
create_prorationsCredit unused time, charge for new plan
noneNo proration, change at next billing cycle
always_invoiceInvoice immediately for the change

Pause Subscription​

POST /api/v1/sales/subscriptions/:subscription_id/pause

Request Body:

{
"resume_at": "2026-03-01T00:00:00Z"
}

Resume Subscription​

POST /api/v1/sales/subscriptions/:subscription_id/resume

Cancel Subscription​

POST /api/v1/sales/subscriptions/:subscription_id/cancel

Request Body:

{
"cancel_at_period_end": true,
"reason": "Too expensive",
"feedback": "Will reconsider when budget allows"
}

Reactivate Subscription​

Reactivate a subscription that was scheduled for cancellation:

POST /api/v1/sales/subscriptions/:subscription_id/reactivate

Subscription Plans​

Define your pricing tiers and billing configurations.

Plan Object​

{
"data": {
"id": "plan-uuid",
"type": "plans",
"attributes": {
"name": "Pro Plan",
"description": "For growing teams",
"product_id": "prod-123",
"currency": "USD",
"amount": 4999,
"interval": "month",
"interval_count": 1,
"trial_period_days": 14,
"usage_type": "licensed",
"billing_scheme": "per_unit",
"features": [
"Unlimited projects",
"Priority support",
"Advanced analytics"
],
"metadata": {},
"active": true,
"created_at": "2026-01-01T00:00:00Z"
}
}
}

Billing Intervals​

IntervalDescription
dayDaily billing
weekWeekly billing
monthMonthly billing
yearAnnual billing

Usage Types​

TypeDescription
licensedFixed quantity billing (per seat)
meteredUsage-based billing

Create Plan​

POST /api/v1/sales/plans

Request Body:

{
"data": {
"type": "plans",
"attributes": {
"name": "Enterprise",
"description": "For large organizations",
"product_id": "prod-123",
"currency": "USD",
"amount": 19999,
"interval": "month",
"interval_count": 1,
"trial_period_days": 30,
"usage_type": "licensed",
"features": [
"Unlimited everything",
"24/7 support",
"Custom integrations",
"SLA guarantee"
]
}
}
}

List Plans​

GET /api/v1/sales/plans

Query Parameters:

ParameterTypeDescription
filter[active]booleanFilter active/inactive plans
filter[product_id]stringFilter by product
filter[interval]stringFilter by billing interval

Update Plan​

PATCH /api/v1/sales/plans/:plan_id
caution

Updating a plan's price does not affect existing subscriptions. Create a new plan for new pricing.

Archive Plan​

POST /api/v1/sales/plans/:plan_id/archive

Usage Records (Metered Billing)​

Track usage for metered subscriptions.

Usage Record Object​

{
"data": {
"id": "usage-uuid",
"type": "usage_records",
"attributes": {
"subscription_id": "sub-123",
"quantity": 1500,
"action": "increment",
"timestamp": "2026-01-02T12:00:00Z",
"metadata": {
"api_calls": 1000,
"storage_gb": 5
}
}
}
}

Report Usage​

POST /api/v1/sales/subscriptions/:subscription_id/usage

Request Body:

{
"data": {
"type": "usage_records",
"attributes": {
"quantity": 500,
"action": "increment",
"timestamp": "2026-01-02T12:00:00Z",
"metadata": {
"feature": "api_calls"
}
}
}
}

Actions:

ActionDescription
incrementAdd to current usage
setOverride current usage

Get Usage Summary​

GET /api/v1/sales/subscriptions/:subscription_id/usage/summary

Query Parameters:

ParameterTypeDescription
period_startdatetimeStart of period
period_enddatetimeEnd of period

Payments​

Process payments securely with Stripe integration.

Payment Object​

{
"data": {
"id": "pay-uuid",
"type": "payments",
"attributes": {
"amount": 4999,
"currency": "USD",
"status": "succeeded",
"payment_method_type": "card",
"card_brand": "visa",
"card_last4": "4242",
"stripe_payment_intent_id": "pi_xxx",
"order_id": "order-123",
"subscription_id": null,
"invoice_id": "inv-123",
"failure_code": null,
"failure_message": null,
"metadata": {},
"created_at": "2026-01-02T12:00:00Z"
}
}
}

Payment Statuses​

StatusDescription
pendingPayment initiated
processingPayment being processed
succeededPayment successful
failedPayment failed
cancelledPayment cancelled
refundedPayment refunded
partially_refundedPartial refund issued

Create Payment​

POST /api/v1/sales/payments

Request Body:

{
"data": {
"type": "payments",
"attributes": {
"amount": 9999,
"currency": "USD",
"payment_method_id": "pm_xxx",
"order_id": "order-123",
"metadata": {
"description": "Order payment"
}
}
}
}

Get Payment​

GET /api/v1/sales/payments/:payment_id

List Payments​

GET /api/v1/sales/payments

Query Parameters:

ParameterTypeDescription
filter[user_id]stringFilter by user
filter[status]stringFilter by status
filter[order_id]stringFilter by order
filter[subscription_id]stringFilter by subscription
filter[created_after]datetimePayments after date
filter[created_before]datetimePayments before date
sortstringSort field
page[number]integerPage number
page[size]integerItems per page

Refund Payment​

POST /api/v1/sales/payments/:payment_id/refund

Request Body:

{
"amount": 2500,
"reason": "customer_request",
"metadata": {
"refund_reason": "Product not as described"
}
}

Refund Reasons:

ReasonDescription
duplicateDuplicate charge
fraudulentFraudulent transaction
customer_requestCustomer requested refund

Payment Methods​

Manage customer payment methods.

Payment Method Object​

{
"data": {
"id": "pm-uuid",
"type": "payment_methods",
"attributes": {
"user_id": "user-123",
"type": "card",
"card": {
"brand": "visa",
"last4": "4242",
"exp_month": 12,
"exp_year": 2028,
"funding": "credit"
},
"billing_details": {
"name": "John Doe",
"email": "john@example.com"
},
"is_default": true,
"stripe_payment_method_id": "pm_xxx",
"created_at": "2026-01-02T12:00:00Z"
}
}
}

Add Payment Method​

POST /api/v1/sales/payment-methods

Request Body:

{
"data": {
"type": "payment_methods",
"attributes": {
"user_id": "user-123",
"stripe_payment_method_id": "pm_xxx",
"set_as_default": true
}
}
}

List User Payment Methods​

GET /api/v1/sales/users/:user_id/payment-methods

Set Default Payment Method​

POST /api/v1/sales/payment-methods/:payment_method_id/set-default

Delete Payment Method​

DELETE /api/v1/sales/payment-methods/:payment_method_id

Invoices​

Automated invoice generation and management.

Invoice Object​

{
"data": {
"id": "inv-uuid",
"type": "invoices",
"attributes": {
"invoice_number": "INV-2026-00001",
"user_id": "user-123",
"subscription_id": "sub-123",
"status": "paid",
"currency": "USD",
"subtotal": 4999,
"discount_amount": 0,
"tax_amount": 400,
"total": 5399,
"amount_paid": 5399,
"amount_due": 0,
"billing_reason": "subscription_cycle",
"period_start": "2026-01-02T00:00:00Z",
"period_end": "2026-02-02T00:00:00Z",
"due_date": "2026-01-16T00:00:00Z",
"paid_at": "2026-01-02T12:00:00Z",
"pdf_url": "https://api.23blocks.com/invoices/inv-uuid.pdf",
"hosted_invoice_url": "https://pay.23blocks.com/inv-uuid",
"metadata": {},
"created_at": "2026-01-02T00:00:00Z"
},
"relationships": {
"line_items": {
"data": [
{ "type": "invoice_items", "id": "ii-1" }
]
},
"payment": {
"data": { "type": "payments", "id": "pay-1" }
}
}
}
}

Invoice Statuses​

StatusDescription
draftInvoice being prepared
openInvoice sent, awaiting payment
paidInvoice paid in full
voidInvoice voided
uncollectibleInvoice marked uncollectible

Get Invoice​

GET /api/v1/sales/invoices/:invoice_id

Query Parameters:

ParameterTypeDescription
includestringInclude: line_items, payment, subscription

List Invoices​

GET /api/v1/sales/invoices

Query Parameters:

ParameterTypeDescription
filter[user_id]stringFilter by user
filter[subscription_id]stringFilter by subscription
filter[status]stringFilter by status
filter[due_after]datetimeInvoices due after date
filter[due_before]datetimeInvoices due before date
sortstringSort field
page[number]integerPage number
page[size]integerItems per page

Download Invoice PDF​

GET /api/v1/sales/invoices/:invoice_id/pdf

Response: PDF file download

Send Invoice​

POST /api/v1/sales/invoices/:invoice_id/send

Sends the invoice to the customer via email.

Void Invoice​

POST /api/v1/sales/invoices/:invoice_id/void

Create Manual Invoice​

POST /api/v1/sales/invoices

Request Body:

{
"data": {
"type": "invoices",
"attributes": {
"user_id": "user-123",
"due_date": "2026-01-16T00:00:00Z",
"line_items": [
{
"description": "Consulting services",
"quantity": 10,
"unit_price": 15000
},
{
"description": "Setup fee",
"quantity": 1,
"unit_price": 50000
}
],
"metadata": {
"project": "Website redesign"
}
}
}
}

Discounts & Coupons​

Create promotional codes and discounts.

Discount Object​

{
"data": {
"id": "disc-uuid",
"type": "discounts",
"attributes": {
"code": "SUMMER20",
"name": "Summer Sale 20% Off",
"type": "percentage",
"value": 20,
"currency": "USD",
"max_redemptions": 1000,
"redemptions_count": 456,
"applies_to": "all",
"minimum_amount": 5000,
"valid_from": "2026-06-01T00:00:00Z",
"valid_until": "2026-08-31T23:59:59Z",
"active": true,
"created_at": "2026-05-01T00:00:00Z"
}
}
}

Discount Types​

TypeDescription
percentagePercentage off (e.g., 20% off)
fixed_amountFixed amount off (e.g., $10 off)

Create Discount​

POST /api/v1/sales/discounts

Request Body:

{
"data": {
"type": "discounts",
"attributes": {
"code": "WELCOME10",
"name": "Welcome Discount",
"type": "percentage",
"value": 10,
"max_redemptions": 500,
"applies_to": "first_order",
"minimum_amount": 2500,
"valid_until": "2026-12-31T23:59:59Z"
}
}
}

Validate Discount Code​

POST /api/v1/sales/discounts/validate

Request Body:

{
"code": "SUMMER20",
"cart_id": "cart-123",
"user_id": "user-123"
}

Response:

{
"valid": true,
"discount": {
"type": "percentage",
"value": 20,
"calculated_amount": 1799
}
}

List Discounts​

GET /api/v1/sales/discounts

Deactivate Discount​

POST /api/v1/sales/discounts/:discount_id/deactivate

Checkout​

Complete checkout flow from cart to order.

Create Checkout Session​

POST /api/v1/sales/checkout/sessions

Request Body:

{
"data": {
"type": "checkout_sessions",
"attributes": {
"cart_id": "cart-123",
"success_url": "https://yourapp.com/success?session={session_id}",
"cancel_url": "https://yourapp.com/cart",
"mode": "payment",
"allow_guest_checkout": true,
"collect_shipping_address": true,
"shipping_options": [
{
"id": "standard",
"name": "Standard Shipping",
"amount": 999,
"delivery_estimate": "5-7 business days"
},
{
"id": "express",
"name": "Express Shipping",
"amount": 2499,
"delivery_estimate": "2-3 business days"
}
]
}
}
}

Checkout Modes:

ModeDescription
paymentOne-time payment
subscriptionRecurring subscription
setupSetup payment method only

Response:

{
"data": {
"id": "cs-uuid",
"type": "checkout_sessions",
"attributes": {
"url": "https://checkout.23blocks.com/cs-uuid",
"expires_at": "2026-01-02T13:00:00Z",
"status": "open"
}
}
}

Get Checkout Session​

GET /api/v1/sales/checkout/sessions/:session_id

Complete Checkout (API)​

For custom checkout UIs:

POST /api/v1/sales/checkout/complete

Request Body:

{
"data": {
"type": "checkout",
"attributes": {
"cart_id": "cart-123",
"payment_method_id": "pm_xxx",
"billing_address": {
"name": "John Doe",
"line1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "US"
},
"shipping_address": {
"name": "John Doe",
"line1": "123 Main St",
"city": "San Francisco",
"state": "CA",
"postal_code": "94102",
"country": "US"
},
"shipping_option_id": "express",
"discount_code": "SAVE20",
"email": "john@example.com"
}
}
}

Response: 201 Created with order object

Calculate Taxes​

POST /api/v1/sales/checkout/calculate-taxes

Request Body:

{
"cart_id": "cart-123",
"shipping_address": {
"postal_code": "94102",
"country": "US",
"state": "CA"
}
}

Response:

{
"subtotal": 8997,
"tax_amount": 742,
"tax_rate": 8.25,
"tax_breakdown": [
{ "name": "State Tax", "rate": 6.0, "amount": 540 },
{ "name": "County Tax", "rate": 1.25, "amount": 112 },
{ "name": "City Tax", "rate": 1.0, "amount": 90 }
],
"total": 9739
}

Webhooks​

Receive real-time notifications for sales events.

Available Events​

EventDescription
cart.createdNew cart created
cart.updatedCart modified
cart.abandonedCart abandoned (no activity)
order.createdNew order placed
order.paidOrder payment received
order.shippedOrder shipped
order.deliveredOrder delivered
order.cancelledOrder cancelled
order.refundedOrder refunded
subscription.createdNew subscription created
subscription.updatedSubscription modified
subscription.trial_endingTrial ending in 3 days
subscription.cancelledSubscription cancelled
subscription.pausedSubscription paused
subscription.resumedSubscription resumed
payment.succeededPayment successful
payment.failedPayment failed
payment.refundedPayment refunded
invoice.createdInvoice generated
invoice.paidInvoice paid
invoice.payment_failedInvoice payment failed
invoice.upcomingInvoice will be sent soon

Webhook Payload​

{
"id": "evt-uuid",
"type": "subscription.created",
"created_at": "2026-01-02T12:00:00Z",
"data": {
"id": "sub-123",
"type": "subscriptions",
"attributes": {
"user_id": "user-123",
"plan_id": "plan-pro",
"status": "trialing"
}
}
}

Configure Webhooks​

POST /api/v1/sales/webhooks

Request Body:

{
"data": {
"type": "webhooks",
"attributes": {
"url": "https://yourapp.com/webhooks/sales",
"events": [
"subscription.created",
"subscription.cancelled",
"payment.succeeded",
"payment.failed"
],
"secret": "whsec_xxx"
}
}
}

Verify Webhook Signature​

import { verifyWebhookSignature } from '@23blocks/sdk';

const isValid = verifyWebhookSignature(
payload,
signature,
webhookSecret
);

SDK Examples​

Complete E-commerce Flow​

import { create23BlocksClient } from '@23blocks/sdk';

const client = create23BlocksClient({
urls: { sales: 'https://sales.api.us.23blocks.com' },
appId: 'your-app-id',
apiKey: 'your-api-key',
});

// 1. Create cart and add items
const cart = await client.sales.createCart({
userId: 'user-123',
currency: 'USD'
});

await client.sales.addCartItem(cart.id, {
productId: 'prod-shirt',
quantity: 2,
unitPrice: 29.99,
metadata: { size: 'L', color: 'blue' }
});

await client.sales.addCartItem(cart.id, {
productId: 'prod-hat',
quantity: 1,
unitPrice: 19.99
});

// 2. Apply discount
await client.sales.applyDiscount(cart.id, {
code: 'SAVE10'
});

// 3. Calculate taxes
const taxes = await client.sales.calculateTaxes(cart.id, {
shippingAddress: {
postalCode: '94102',
country: 'US',
state: 'CA'
}
});

// 4. Create checkout session
const session = await client.sales.createCheckoutSession({
cartId: cart.id,
successUrl: 'https://yourapp.com/success',
cancelUrl: 'https://yourapp.com/cart',
collectShippingAddress: true
});

// Redirect customer to session.url

Subscription Management​

// Create subscription with trial
const subscription = await client.sales.createSubscription({
userId: 'user-123',
planId: 'plan-pro-monthly',
paymentMethodId: 'pm_xxx',
trialDays: 14,
metadata: { referral: 'partner-123' }
});

// Upgrade subscription
await client.sales.updateSubscription(subscription.id, {
planId: 'plan-enterprise-monthly',
prorationBehavior: 'create_prorations'
});

// Add seats
await client.sales.updateSubscription(subscription.id, {
quantity: 10
});

// Cancel at period end
await client.sales.cancelSubscription(subscription.id, {
cancelAtPeriodEnd: true,
reason: 'Switching to competitor'
});

// Reactivate before period ends
await client.sales.reactivateSubscription(subscription.id);

Usage-Based Billing​

// Report API usage
await client.sales.reportUsage(subscription.id, {
quantity: 1500,
action: 'increment',
timestamp: new Date().toISOString(),
metadata: { feature: 'api_calls' }
});

// Get usage summary
const usage = await client.sales.getUsageSummary(subscription.id, {
periodStart: '2026-01-01T00:00:00Z',
periodEnd: '2026-01-31T23:59:59Z'
});

console.log(`Total API calls: ${usage.total}`);

Invoice Management​

// List user invoices
const invoices = await client.sales.listInvoices({
filter: { userId: 'user-123', status: 'paid' },
sort: '-created_at',
page: { number: 1, size: 10 }
});

// Download invoice PDF
const pdfBlob = await client.sales.downloadInvoicePdf('inv-123');

// Create manual invoice
const invoice = await client.sales.createInvoice({
userId: 'user-123',
dueDate: '2026-01-16T00:00:00Z',
lineItems: [
{ description: 'Consulting', quantity: 8, unitPrice: 15000 },
{ description: 'Setup', quantity: 1, unitPrice: 25000 }
]
});

// Send invoice
await client.sales.sendInvoice(invoice.id);

Payment Processing​

// Add payment method
const paymentMethod = await client.sales.addPaymentMethod({
userId: 'user-123',
stripePaymentMethodId: 'pm_xxx',
setAsDefault: true
});

// Process one-time payment
const payment = await client.sales.createPayment({
amount: 9999,
currency: 'USD',
paymentMethodId: paymentMethod.id,
metadata: { description: 'Custom service' }
});

// Refund payment
await client.sales.refundPayment(payment.id, {
amount: 5000, // Partial refund
reason: 'customer_request'
});

Error Handling​

Error Response Format​

{
"errors": [
{
"status": "422",
"code": "insufficient_funds",
"title": "Payment Failed",
"detail": "The card has insufficient funds to complete this transaction.",
"meta": {
"decline_code": "insufficient_funds",
"payment_intent_id": "pi_xxx"
}
}
]
}

Common Error Codes​

CodeHTTP StatusDescription
cart_not_found404Cart does not exist
cart_expired410Cart has expired
cart_empty422Cannot checkout empty cart
invalid_quantity422Quantity must be positive
insufficient_inventory422Product out of stock
invalid_discount422Discount code invalid or expired
discount_minimum_not_met422Order doesn't meet minimum for discount
payment_failed422Payment could not be processed
card_declined422Card was declined
insufficient_funds422Card has insufficient funds
subscription_not_found404Subscription does not exist
plan_not_found404Plan does not exist
plan_inactive422Plan is no longer available
subscription_cancelled422Cannot modify cancelled subscription
invoice_already_paid422Invoice has already been paid

Rate Limits​

EndpointLimit
Cart operations100 requests/minute
Order creation30 requests/minute
Payment processing50 requests/minute
Subscription operations60 requests/minute
Usage reporting300 requests/minute
Webhook endpoints1000 events/minute

Best Practices​

Cart Management​

  • Set appropriate cart expiration times (default: 7 days)
  • Clear abandoned carts periodically
  • Validate inventory before checkout

Subscription Billing​

  • Always offer trial periods for new customers
  • Use proration for plan changes
  • Send reminder emails before trial ends
  • Handle failed payments with retry logic

Payment Security​

  • Never store full card numbers
  • Use Stripe's tokenization
  • Verify webhook signatures
  • Implement idempotency keys for payments

Checkout Optimization​

  • Minimize checkout steps
  • Offer guest checkout
  • Pre-fill known customer data
  • Show clear pricing breakdown


Support​

Use This Block with AI Agents​

This block ships an official Claude Code plugin from the public 23blocks marketplace (19 plugins, 205 skills). Your agent gets full working knowledge of this API — endpoints, identity registration, and conventions.

# one-time: add the 23blocks marketplace
claude plugin marketplace add https://github.com/23blocks-OS/ai-agents

# install this block's plugin
claude plugin install sales-block

Configure BLOCKS_API_URL, BLOCKS_API_KEY, and BLOCKS_AUTH_TOKEN. Register identity first: each block is autonomous — register the user with this block's identity endpoint before private calls (only user_unique_id is required; email/phone are optional notification-routing fields).

Full reference: AI Agents & Claude Code Plugins · github.com/23blocks-OS/ai-agents