Sale Orders
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 Stripe or MercadoPago.
Creating a Sale Order
Endpoint
POST /integration-api/v1/orders
Required Fields
| Field | Type | Description | Required |
|---|---|---|---|
type | string | Must be "sale" | Yes |
return_url | string | URL to redirect user after payment | Yes |
unit_price | float | Total order price | Yes |
currency_id | string | Order currency (ISO 4217 code) | Yes |
user | object | User information | Yes |
user.id | string | User unique ID (max 64 chars) | Yes |
user.email | string | User's email address | Yes |
products | array | Array of products in the order | Yes |
products.*.id | string | Product unique ID (max 64 chars) | Yes |
products.*.type | string | Product type: content or subscription | Yes |
products.*.unit_price | float | Individual product price | Yes |
products.*.currency_id | string | Product currency (ISO 4217 code) | Yes |
Optional Fields
| Field | Type | Description |
|---|---|---|
external_reference | string | Your unique order identifier (max 64 chars) |
products.*.name | string | Product name (required for auto-creation) |
products.*.url | string | Product URL (required for auto-creation) |
For sale orders, if a product doesn't exist and you provide both name and url, the product will be created automatically.
Request Example
Basic Sale Order
{
"type": "sale",
"external_reference": "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": [
{
"id": "PREMIUM-EBOOK",
"type": "content",
"name": "Complete Marketing Guide",
"url": "https://yourstore.com/products/marketing-guide",
"unit_price": 29.99,
"currency_id": "USD"
}
]
}
Sale Order with Subscription
{
"type": "sale",
"external_reference": "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": [
{
"id": "MONTHLY-PREMIUM",
"type": "subscription",
"unit_price": 9.99,
"currency_id": "USD"
}
]
}
Sale Order for Different Currencies
Currency determines which payment gateway is used:
ARS (Argentine Peso) → MercadoPago:
{
"type": "sale",
"external_reference": "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": [
{
"id": "LIBRO-DIGITAL",
"type": "content",
"unit_price": 5000.00,
"currency_id": "ARS"
}
]
}
USD (US Dollar) → Stripe:
{
"type": "sale",
"external_reference": "USD-ORDER-321",
"return_url": "https://yourstore.com/thank-you",
"unit_price": 19.99,
"currency_id": "USD",
"user": {
"id": "user-us-789",
"email": "[email protected]"
},
"products": [
{
"id": "DIGITAL-COURSE",
"type": "content",
"unit_price": 19.99,
"currency_id": "USD"
}
]
}
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. If you want to disable these automatic emails, you can turn them off in your dashboard at /dashboard/settings#notifications.
Response
Success Response (201 Created)
When a sale order is created successfully, you receive:
{
"data": {
"id": "a4b5c6d7-e8f9-4a0b-bc1d-e2f3a4b5c6d7",
"external_reference": "WEB-ORDER-12345",
"checkout": {
"url": "https://yourstore.publica.la/auth/token?external-auth-token=eyJ0eXAiOiJKV1QiLCJhbGc...",
"ttl": 3600
},
"type": "sale",
"unit_price": 29.99,
"currency_id": "USD",
"status": "pending",
"created_at": "2024-11-24",
"user": {
"id": "user-ext-789",
"email": "[email protected]"
},
"products": [
{
"id": "PREMIUM-EBOOK",
"type": "content",
"name": "Complete Marketing Guide",
"status": "pending",
"cover": "https://cdn.publica.la/content/marketing-guide.jpg",
"reader_url": "https://yourstore.publica.la/reader/marketing-guide",
"description": "Comprehensive guide to digital marketing",
"pages_quantity": 450,
"file_type": "pdf",
"unit_price": 29.99,
"currency_id": "USD"
}
]
}
}
Critical Response Fields
| Field | Type | Description |
|---|---|---|
checkout.url | string | Redirect user here to complete payment |
checkout.ttl | integer | Seconds until checkout URL expires (typically 3600 = 1 hour) |
status | string | Initially "pending", becomes "approved" after payment |
external | null | Always null for sale orders (not applicable) |
You MUST redirect the user to checkout.url to complete the payment. The URL contains an authentication token and will expire after the TTL period.
Checkout Flow
- Create order via API → Receive
checkout.url - Redirect user to
checkout.url - User completes payment through gateway
- User redirected to
return_urlwithorder_idandstatusparameters - Verify order status via API
Managing Sale Orders
Checking Order Status
# Get specific order status
GET /integration-api/v1/orders/{order_id}
Response will show current status:
{
"data": {
"id": "a4b5c6d7-...",
"status": "approved", // or "pending", "cancelled"
...
}
}
Listing Sale Orders
# List all orders (includes sale orders)
GET /integration-api/v1/orders
# Filter by status
GET /integration-api/v1/orders?status=pending
Updating Sale Orders
Once approved, you can update the expiration date for all products in a sale order.
Endpoint:
PUT /integration-api/v1/orders/{order_id}
Path Parameters:
| Parameter | Description |
|---|---|
order_id | The order's UUID (from id field) or external reference (from external_reference field) |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
id_type | string | internal | Use internal when order_id is a UUID, or external when it's an external reference |
Request Body:
| Field | Type | Description | Required |
|---|---|---|---|
expiration_date | string | New expiration date (YYYY-MM-DD format) | Yes |
Example - Update using UUID:
PUT /integration-api/v1/orders/a4b5c6d7-e8f9-4a0b-bc1d-e2f3a4b5c6d7?id_type=internal
{
"expiration_date": "2025-12-31"
}
Example - Update using external reference:
PUT /integration-api/v1/orders/WEB-ORDER-789?id_type=external
{
"expiration_date": "2025-12-31"
}
Response (200 OK): Returns the updated order with modified expiration date applied to all products.
Note: This endpoint updates the expiration date for ALL products in the order.
Canceling Sale Orders
DELETE /integration-api/v1/orders/{order_id}
{
"reason": "Customer requested refund"
}
Supported Payment Gateways
| Currency | Gateway | Supported Countries |
|---|---|---|
| USD | Stripe | Global |
| ARS | MercadoPago | Argentina |
| CLP | Flow (via MercadoPago) | Chile |
| COP | PayU | Colombia |
| MXN | MercadoPago | Mexico |
| BRL | MercadoPago | Brazil |
The payment gateway is automatically selected based on the currency_id you specify in the order.
Error Handling
Common Errors
| Status Code | Error | Cause |
|---|---|---|
400 | Invalid currency | Currency not supported or misconfigured |
401 | Unauthorized | Invalid or missing API token |
422 | Validation error | Missing required fields |
422 | Invalid product | Product doesn't exist and auto-creation failed |
422 | Currency mismatch | Products have different currencies |
Error Response Example
{
"status": 422,
"errors": [
{
"title": "The currency_id must be consistent across all products",
"details": [
"All products in a sale order must use the same currency"
]
}
]
}
Related Documentation
- Overview - Compare all order types
- Permission Orders - Grant access without payment records
- Report Orders - Assign content + record payment
- API Authentication - Authentication setup