Verso-Backend provides a comprehensive REST API for programmatic access to leads, orders, products, appointments, and webhooks.
All API endpoints require Bearer Token authentication. Include your API key in the Authorization header:
Authorization: Bearer sk_live_your_api_key_here- Navigate to Admin Dashboard → Settings → API Keys
- Click Generate New Key
- Select the required scopes (permissions)
- Copy and securely store the key (it won't be shown again)
| Scope | Permission |
|---|---|
read:leads |
View contact form submissions |
write:leads |
Create and update leads |
read:orders |
View orders |
write:orders |
Update order status |
read:products |
View product catalog |
write:products |
Create and update products |
read:appointments |
View appointments |
write:appointments |
Create and update appointments |
manage:webhooks |
Configure outbound webhooks |
https://your-domain.com/api/v1
Development:
http://localhost:5000/api/v1
API requests are rate limited to prevent abuse:
| Operation Type | Limit |
|---|---|
| Read operations (GET) | 100 requests/minute |
| Write operations (POST, PATCH, DELETE) | 30 requests/minute |
Rate limit information is included in response headers:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum requests allowed |
X-RateLimit-Remaining |
Requests remaining in current window |
X-RateLimit-Reset |
Unix timestamp when limit resets |
Example Response Headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1702345678When rate limited, the API returns 429 Too Many Requests.
List endpoints support pagination via query parameters:
| Parameter | Default | Maximum | Description |
|---|---|---|---|
page |
1 | - | Page number (1-indexed) |
per_page |
25 | 100 | Items per page |
Example Request:
curl "https://your-domain.com/api/v1/products?page=2&per_page=50" \
-H "Authorization: Bearer sk_live_..."Paginated Response Format:
{
"data": [...],
"pagination": {
"page": 2,
"per_page": 50,
"total": 230,
"pages": 5
}
}The API uses standard HTTP status codes and returns errors in a consistent format.
| Code | Meaning |
|---|---|
200 |
Success |
201 |
Created |
400 |
Bad Request - Invalid parameters |
401 |
Unauthorized - Missing or invalid API key |
403 |
Forbidden - Valid key but insufficient scope |
404 |
Not Found - Resource doesn't exist |
422 |
Unprocessable Entity - Validation error |
429 |
Too Many Requests - Rate limit exceeded |
500 |
Internal Server Error |
{
"error": "Error message description",
"code": "ERROR_CODE",
"details": {
"field": "Additional context"
}
}Example Error:
{
"error": "Lead not found",
"code": "NOT_FOUND"
}Contact form submissions and CRM lead management.
GET /api/v1/leadsScope Required: read:leads
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
page |
integer | Page number |
per_page |
integer | Items per page (max 100) |
status |
string | Filter by status |
sort |
string | Sort field (default: submitted_at) |
order |
string | asc or desc (default: desc) |
created_after |
datetime | Filter by creation date |
created_before |
datetime | Filter by creation date |
Example Request:
curl "https://your-domain.com/api/v1/leads?status=New&per_page=10" \
-H "Authorization: Bearer sk_live_..."Response:
{
"data": [
{
"id": 1,
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+1-555-123-4567",
"message": "Interested in your services",
"status": "New",
"source": "website",
"notes": null,
"tags": ["enterprise", "urgent"],
"submitted_at": "2024-12-01T10:30:00Z"
}
],
"pagination": {
"page": 1,
"per_page": 10,
"total": 45,
"pages": 5
}
}GET /api/v1/leads/{id}Scope Required: read:leads
Example Request:
curl "https://your-domain.com/api/v1/leads/1" \
-H "Authorization: Bearer sk_live_..."Response:
{
"id": 1,
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+1-555-123-4567",
"message": "Interested in your services",
"status": "New",
"source": "website",
"notes": null,
"tags": ["enterprise"],
"submitted_at": "2024-12-01T10:30:00Z"
}POST /api/v1/leadsScope Required: write:leads
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
first_name |
string | Yes | First name |
last_name |
string | Yes | Last name |
email |
string | Yes | Email address |
phone |
string | Yes | Phone number |
message |
string | Yes | Lead message/inquiry |
status |
string | No | Lead status (default: "New") |
source |
string | No | Lead source (default: "api") |
notes |
string | No | Internal notes |
tags |
array | No | Array of tag strings |
Example Request:
curl -X POST "https://your-domain.com/api/v1/leads" \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@example.com",
"phone": "+1-555-987-6543",
"message": "Looking for enterprise pricing",
"tags": ["enterprise", "priority"]
}'Response (201 Created):
{
"id": 46,
"message": "Lead created successfully"
}PATCH /api/v1/leads/{id}Scope Required: write:leads
Only include fields you want to update.
Example Request:
curl -X PATCH "https://your-domain.com/api/v1/leads/1" \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"status": "Contacted",
"notes": "Called on 12/5, follow up scheduled"
}'Response:
{
"id": 1,
"message": "Lead updated successfully"
}E-commerce order management.
GET /api/v1/ordersScope Required: read:orders
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status (pending, paid, shipped, etc.) |
created_after |
datetime | Filter by creation date |
created_before |
datetime | Filter by creation date |
page |
integer | Page number |
per_page |
integer | Items per page |
Example Request:
curl "https://your-domain.com/api/v1/orders?status=paid" \
-H "Authorization: Bearer sk_live_..."Response:
{
"data": [
{
"id": 101,
"order_number": "ORD-2024-0101",
"status": "paid",
"total_amount": 2999,
"currency": "usd",
"email": "customer@example.com",
"tracking_number": null,
"created_at": "2024-12-01T12:30:00Z",
"items_count": 2
}
],
"pagination": {
"page": 1,
"per_page": 25,
"total": 150,
"pages": 6
}
}GET /api/v1/orders/{id}Scope Required: read:orders
Returns order details including line items.
Response:
{
"id": 101,
"order_number": "ORD-2024-0101",
"status": "paid",
"total_amount": 2999,
"subtotal_amount": 2999,
"discount_amount": 0,
"tax_amount": 0,
"shipping_amount": 0,
"currency": "usd",
"email": "customer@example.com",
"tracking_number": null,
"shipping_address": {
"line1": "123 Main St",
"city": "Springfield",
"state": "IL",
"postal_code": "62701",
"country": "US"
},
"items": [
{
"id": 1,
"product_id": 10,
"product_name": "Premium Widget",
"quantity": 2,
"unit_price": 1499
}
],
"created_at": "2024-12-01T12:30:00Z"
}PATCH /api/v1/orders/{id}Scope Required: write:orders
Update order status or fulfillment details.
Request Body:
| Field | Type | Description |
|---|---|---|
status |
string | Order status |
tracking_number |
string | Shipping tracking number |
fulfillment_status |
string | Fulfillment status |
Example Request:
curl -X PATCH "https://your-domain.com/api/v1/orders/101" \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"status": "shipped",
"tracking_number": "1Z999AA10123456784"
}'Product catalog management.
GET /api/v1/productsScope Required: read:products
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
is_digital |
boolean | Filter digital/physical products |
in_stock |
boolean | Filter by stock availability |
category_id |
integer | Filter by category |
page |
integer | Page number |
per_page |
integer | Items per page |
Response:
{
"data": [
{
"id": 10,
"name": "Premium Widget",
"slug": "premium-widget",
"description": "A high-quality widget for professionals",
"price": 4999,
"compare_at_price": null,
"inventory_count": 50,
"is_digital": false,
"is_active": true,
"category_id": 3
}
],
"pagination": {...}
}GET /api/v1/products/{id}Scope Required: read:products
POST /api/v1/productsScope Required: write:products
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Product name |
price |
integer | Yes | Price in cents |
description |
string | No | Product description |
sku |
string | No | Stock keeping unit |
inventory_count |
integer | No | Stock quantity (default: 0) |
is_digital |
boolean | No | Digital product flag |
category_id |
integer | No | Category ID |
Example Request:
curl -X POST "https://your-domain.com/api/v1/products" \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "New Widget",
"price": 2999,
"description": "Our latest widget model",
"inventory_count": 100
}'PATCH /api/v1/products/{id}Scope Required: write:products
Scheduling and booking management.
GET /api/v1/appointmentsScope Required: read:appointments
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status |
estimator_id |
integer | Filter by assigned estimator |
date_from |
date | Start of date range |
date_to |
date | End of date range |
Response:
{
"data": [
{
"id": 1,
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+1-555-123-4567",
"scheduled_time": "2024-12-10T14:00:00Z",
"duration_minutes": 60,
"status": "scheduled",
"service_id": 1,
"estimator_id": 2,
"notes": null
}
],
"pagination": {...}
}Configure outbound webhooks to receive notifications about events.
GET /api/v1/webhooksScope Required: manage:webhooks
POST /api/v1/webhooksScope Required: manage:webhooks
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Webhook name |
url |
string | Yes | Endpoint URL |
events |
array | Yes | Events to subscribe to |
secret |
string | No | HMAC signing secret |
is_active |
boolean | No | Active status (default: true) |
Available Events:
lead.created- New lead submittedlead.updated- Lead status changedorder.created- New order placedorder.updated- Order status changedproduct.created- New product addedappointment.created- New appointment bookedappointment.updated- Appointment changed
Example Request:
curl -X POST "https://your-domain.com/api/v1/webhooks" \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Order Notifications",
"url": "https://your-server.com/webhooks/verso",
"events": ["order.created", "order.updated"],
"secret": "whsec_your_signing_secret"
}'import requests
API_KEY = "sk_live_your_api_key"
BASE_URL = "https://your-domain.com/api/v1"
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
# Get all leads
response = requests.get(f"{BASE_URL}/leads", headers=headers)
leads = response.json()["data"]
# Create a lead
new_lead = {
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@example.com",
"phone": "+1-555-987-6543",
"message": "API test lead"
}
response = requests.post(f"{BASE_URL}/leads", json=new_lead, headers=headers)
print(response.json())const API_KEY = 'sk_live_your_api_key';
const BASE_URL = 'https://your-domain.com/api/v1';
const headers = {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
};
// Get all products
async function getProducts() {
const response = await fetch(`${BASE_URL}/products`, { headers });
const data = await response.json();
return data.data;
}
// Update order status
async function updateOrder(orderId, status, trackingNumber) {
const response = await fetch(`${BASE_URL}/orders/${orderId}`, {
method: 'PATCH',
headers,
body: JSON.stringify({ status, tracking_number: trackingNumber })
});
return response.json();
}For a complete, machine-readable API specification, see openapi.yaml.
Import into tools like Postman, Swagger UI, or Insomnia for interactive API exploration.
Last Updated: December 2024