Sale Orders
Initiate Publica.la's checkout flow where customers pay directly through the platform. Orders start with pending status and transition to approved after successful payment via integrated payment gateways (Stripe, MercadoPago, etc.).
See Choosing the Right Order Type for guidance on when to use sale orders.
Creating a Sale Order
Endpoint
POST /api/v3/orders
Request Body
{
"type": "sale",
"external_id": "CART-12345",
"return_url": "https://yoursite.com/thank-you",
"unit_price": 29.99,
"currency_id": "USD",
"user": {
"id": "customer-123",
"email": "[email protected]"
},
"products": [
{
"type": "content",
"external_id": "9781234567890",
"unit_price": 29.99,
"currency_id": "USD"
}
]
}
Required Fields
| Field | Type | Description |
|---|---|---|
type | string | Must be "sale" |
return_url | string | URL to redirect after payment |
unit_price | float | Total order amount |
currency_id | string | ISO 4217 currency code |
user | object | User information |
user.id | string | User external ID (required) |
products | array | Products in the order |
products[].type | string | content or subscription |
products[].external_id | string | Product external ID |
products[].unit_price | float | Individual product price |
products[].currency_id | string | Product currency |
Optional Fields
| Field | Type | Description |
|---|---|---|
external_id | string | Your unique order ID (max 64 chars) |
user.email | string | User email address |
products[].name | string | Product name (required for auto-creation) |
products[].url | string | External URL (required for auto-creation) |
External Content (Auto-Creation)
If you're selling content hosted outside Publica.la, you can create sale orders without pre-registering the product. When a products[].external_id doesn't exist, the system automatically creates a link-type product using the provided name and url.
This is useful when:
- Content is hosted on your own platform
- You want to track sales in Publica.la without uploading the actual content
- You need to maintain order history for external resources
Example: External Content Sale
curl -X POST "https://yourstore.publica.la/api/v3/orders" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"type": "sale",
"return_url": "https://yourstore.com/confirmation",
"unit_price": 19.99,
"currency_id": "USD",
"user": {
"id": "user-123"
},
"products": [
{
"external_id": "EXTERNAL-COURSE-001",
"type": "content",
"name": "Advanced Photography Course",
"url": "https://yourplatform.com/courses/photography",
"unit_price": 19.99,
"currency_id": "USD"
}
]
}'
The product will be created with external_id: "EXTERNAL-COURSE-001" and readers will be redirected to the provided URL.
Request Examples
Basic Sale Order (USD - Stripe)
curl -X POST "https://yourstore.publica.la/api/v3/orders" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"type": "sale",
"external_id": "WEB-ORDER-12345",
"return_url": "https://yourstore.com/order/confirmation",
"unit_price": 29.99,
"currency_id": "USD",
"user": {
"id": "user-ext-789",
"email": "[email protected]"
},
"products": [
{
"external_id": "PREMIUM-EBOOK",
"type": "content",
"unit_price": 29.99,
"currency_id": "USD"
}
]
}'
Sale Order (ARS - MercadoPago)
curl -X POST "https://yourstore.publica.la/api/v3/orders" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"type": "sale",
"external_id": "ARS-ORDER-789",
"return_url": "https://yourstore.com/gracias",
"unit_price": 5000.00,
"currency_id": "ARS",
"user": {
"id": "user-ar-456",
"email": "[email protected]"
},
"products": [
{
"external_id": "LIBRO-DIGITAL",
"type": "content",
"unit_price": 5000.00,
"currency_id": "ARS"
}
]
}'
Sale Order with Subscription
curl -X POST "https://yourstore.publica.la/api/v3/orders" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"type": "sale",
"external_id": "SUB-ORDER-456",
"return_url": "https://yourstore.com/subscription/welcome",
"unit_price": 9.99,
"currency_id": "USD",
"user": {
"id": "user-sub-123",
"email": "[email protected]"
},
"products": [
{
"external_id": "MONTHLY-PREMIUM",
"type": "subscription",
"unit_price": 9.99,
"currency_id": "USD"
}
]
}'
Sale Order with Multiple Products
curl -X POST "https://yourstore.publica.la/api/v3/orders" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"type": "sale",
"external_id": "CART-BUNDLE-001",
"return_url": "https://yourstore.com/checkout/complete",
"unit_price": 49.97,
"currency_id": "USD",
"user": {
"id": "user-cart-123",
"email": "[email protected]"
},
"products": [
{
"external_id": "EBOOK-001",
"type": "content",
"unit_price": 19.99,
"currency_id": "USD"
},
{
"external_id": "EBOOK-002",
"type": "content",
"unit_price": 14.99,
"currency_id": "USD"
},
{
"external_id": "EBOOK-003",
"type": "content",
"unit_price": 14.99,
"currency_id": "USD"
}
]
}'
Response
Success Response (201 Created)
{
"data": {
"id": "12345",
"uuid": "4db50ffb-80fd-42b1-9bdb-c572e1a5487f",
"external_id": "WEB-ORDER-12345",
"type": "sale",
"status": "pending",
"unit_price": 29.99,
"currency_id": "USD",
"created_at": "2025-12-03T22:44:07.000000Z",
"updated_at": "2025-12-03T22:44:07.000000Z"
}
}
Sale orders are created with status: pending. The order transitions to approved only after the user completes payment.
Response with Checkout URL
Request the checkout URL with ?include=pending_checkout:
{
"data": {
"id": "12345",
"uuid": "4db50ffb-80fd-42b1-9bdb-c572e1a5487f",
"external_id": "WEB-ORDER-12345",
"type": "sale",
"status": "pending",
"unit_price": 29.99,
"currency_id": "USD",
"created_at": "2025-12-03T22:44:07.000000Z",
"updated_at": "2025-12-03T22:44:07.000000Z",
"pending_checkout": {
"url": "https://yourstore.publica.la/auth/token?external-auth-token=eyJ0eXAiOiJKV1QiLCJhbGc...",
"ttl": 3600
}
}
}
Checkout Object Fields
| Field | Type | Description |
|---|---|---|
pending_checkout.url | string | Redirect user here to complete payment |
pending_checkout.ttl | integer | Seconds until URL expires (typically 3600 = 1 hour) |
You MUST redirect the user to pending_checkout.url to complete the payment. The URL contains an authentication token that expires after the TTL period.
Checkout Flow
1. Your App 2. Publica.la 3. Payment Gateway
| | |
|--- POST /api/v3/orders ----->| |
|<--- pending_checkout.url ----| |
| | |
|--- Redirect user ----------->| |
| |--- Payment redirect -------->|
| | |
| |<--- Payment callback --------|
| | |
|<--- Redirect to return_url --| |
| | |
|--- GET /api/v3/orders/{id} ->| |
|<--- status: approved --------| |
Flow Steps
- Create order via API
- Receive
pending_checkout.urlin response - Redirect user to
pending_checkout.url - User completes payment through gateway
- User redirected to your
return_url - Verify order status via API
Return URL Parameters
After payment, user is redirected to your return_url with query parameters:
https://yourstore.com/thank-you?order_id=4db50ffb-80fd-42b1-9bdb-c572e1a5487f&status=approved
| Parameter | Description |
|---|---|
order_id | Publica.la order UUID |
status | Order status (approved, pending, or cancelled) |
Payment Gateways
The payment gateway is automatically selected based on currency_id:
| Currency | Gateway | Supported Countries |
|---|---|---|
| USD | Stripe | Global |
| EUR | Stripe | Global |
| ARS | MercadoPago | Argentina |
| MXN | MercadoPago | Mexico |
| BRL | MercadoPago | Brazil |
| CLP | Flow (via MercadoPago) | Chile |
| COP | PayU | Colombia |
Gateway availability depends on your tenant configuration. Contact support if you need to enable specific gateways.
Order Status Lifecycle
[Create] ─────► pending ──────[User Pays]──────► approved
│ │
└──────[Expires/Cancel]──────► cancelled
| Status | Description |
|---|---|
pending | Order created, awaiting payment |
approved | Payment successful, user has access |
cancelled | Order cancelled or payment failed |
Managing Sale Orders
Check Order Status
curl -X GET "https://yourstore.publica.la/api/v3/orders/4db50ffb-80fd-42b1-9bdb-c572e1a5487f" \
-H "X-User-Token: your-api-token"
List Pending Orders
curl -X GET "https://yourstore.publica.la/api/v3/orders?filter[type]=sale&filter[status]=pending" \
-H "X-User-Token: your-api-token"
Get Checkout URL for Pending Order
If you need to resend the checkout URL:
curl -X GET "https://yourstore.publica.la/api/v3/orders/4db50ffb-80fd-42b1-9bdb-c572e1a5487f?include=pending_checkout" \
-H "X-User-Token: your-api-token"
Update Approved Order Expiration
Once approved, you can update expiration:
curl -X PUT "https://yourstore.publica.la/api/v3/orders/4db50ffb-80fd-42b1-9bdb-c572e1a5487f" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"expiration_date": "2026-12-31"
}'
Cancel Order
curl -X DELETE "https://yourstore.publica.la/api/v3/orders/4db50ffb-80fd-42b1-9bdb-c572e1a5487f" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-d '{
"reason": "Customer requested cancellation"
}'
Email Notifications
When a sale order is successfully paid and approved, an email notification is automatically sent to the user confirming their purchase and providing access details. To disable automatic emails, go to your dashboard at /dashboard/settings#notifications.
Error Handling
Common Errors
| Status | Error | Cause |
|---|---|---|
| 401 | Unauthenticated | Invalid or missing API token |
| 404 | Product not found | Product external ID doesn't exist |
| 422 | user.id required | Sale orders require user.id |
| 422 | user.email required | Sale orders require user.email |
| 422 | Currency mismatch | Product currencies don't match order currency |
| 422 | Invalid currency | Currency not supported or gateway not configured |
Error Response Example
{
"message": "The given data was invalid.",
"errors": {
"user.id": ["The user.id field is required."],
"user.email": ["The user.email field is required."]
}
}
Best Practices
- Store checkout URLs - Cache the checkout URL in case user needs to retry
- Verify status - Always verify order status after return, don't trust URL params alone
- Handle expiration - Checkout URLs expire; be prepared to request a new one
- Set appropriate return_url - Include order ID in return URL for easy lookup
See Also
- Permission Orders - Access without payment
- Report Orders - External sales with payment records
- Update & Cancel - Manage existing orders
- Get Order - Retrieve order details