### Install ngrok and Start Local Webhook Server (Bash)
Source: https://quickbutik.dev/webhooks/setup
This snippet demonstrates how to install ngrok globally using npm and start a local Node.js webhook server. It's essential for exposing your local development environment to external services like Quickbutik for testing.
```bash
# Install ngrok
npm install -g ngrok
# Start your local webhook server
node webhook-server.js
# In another terminal, expose your local server
ngrok http 3000
# Copy the ngrok URL to your Quickbutik webhook settings
# Example: https://abc123.ngrok.io/webhooks/quickbutik
```
--------------------------------
### Quick Start Examples
Source: https://quickbutik.dev/api-v1/authentication
Examples of how to authenticate requests using Basic Authentication in various programming languages.
```APIDOC
## Quick Start
```bash cURL theme={null}
curl https://api.quickbutik.com/v1/orders \
-u your_api_key:your_api_key
```
```javascript Node.js theme={null}
const apiKey = 'your_api_key';
const credentials = Buffer.from(`${apiKey}:${apiKey}`).toString('base64');
fetch('https://api.quickbutik.com/v1/orders', {
headers: {
'Authorization': `Basic ${credentials}`
}
});
```
```python Python theme={null}
import requests
import base64
api_key = 'your_api_key'
credentials = base64.b64encode(f'{api_key}:{api_key}'.encode()).decode()
response = requests.get(
'https://api.quickbutik.com/v1/orders',
headers={'Authorization': f'Basic {credentials}'}
)
```
```php PHP theme={null}
```
```
--------------------------------
### Products Count Example
Source: https://quickbutik.dev/api-v1/introduction
Example of how to fetch the count of products using curl.
```APIDOC
## GET /products/count
### Description
Fetches the total number of products in your store.
### Method
GET
### Endpoint
/products/count
### Parameters
#### Path Parameters
None
#### Query Parameters
None
#### Request Body
None
### Request Example
```bash
curl https://api.quickbutik.com/v1/products/count \
-u your_api_key:your_api_key
```
### Response
#### Success Response (200)
- **count** (string) - The total number of products.
#### Response Example
```json
{
"count": "42"
}
```
```
--------------------------------
### Bash: Setting up ngrok for Local Webhook Testing
Source: https://quickbutik.dev/webhooks/introduction
Provides instructions for setting up ngrok to expose a local development server to the internet for testing webhooks. This involves installing ngrok, starting a local server, and then using ngrok to create a public URL.
```bash
# Install ngrok
npm install -g ngrok
# Start your webhook server
node webhook-server.js
# In another terminal, expose your local server
ngrok http 3000
# Use the ngrok URL in your Quickbutik webhook settings
# Example: https://abc123.ngrok.io/webhooks/quickbutik
```
--------------------------------
### Example Authorization Header Construction
Source: https://quickbutik.dev/api-v1/authentication
Step-by-step example of constructing the Authorization header using an example API key.
```APIDOC
## Example
Let's say your API key is `sk_live_abc123`. Here's how you'd construct the Authorization header:
```text Step 1: Format theme={null}
sk_live_abc123:sk_live_abc123
```
```text Step 2: Base64 encode theme={null}
c2tfbGl2ZV9hYmMxMjM6c2tfbGl2ZV9hYmMxMjM=
```
```text Step 3: Authorization header theme={null}
Authorization: Basic c2tfbGl2ZV9hYmMxMjM6c2tfbGl2ZV9hYmMxMjM=
```
```
--------------------------------
### Dockerfile for Production Webhook Server
Source: https://quickbutik.dev/webhooks/setup
A Dockerfile to containerize the Node.js webhook server. It sets up a production environment using Node.js 18 Alpine, installs dependencies, copies the application code, creates a non-root user for security, and defines a health check.
```dockerfile
FROM node:18-alpine
WORKDIR /app
# Install dependencies
COPY package*.json ./
RUN npm ci --only=production
# Copy application
COPY . .
# Create non-root user
RUN addgroup -g 1001 -S webhook
RUN adduser -S webhook -u 1001
# Security
RUN chown -R webhook:webhook /app
USER webhook
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
EXPOSE 3000
CMD ["node", "webhook-server.js"]
```
--------------------------------
### Basic Local Webhook Server with Express (JavaScript)
Source: https://quickbutik.dev/webhooks/setup
A simple Express.js server setup to receive and log incoming webhook events from Quickbutik. It listens on port 3000 and responds with a 200 OK status. This is suitable for basic local testing.
```javascript
const express = require('express');
const app = express();
app.get('/webhooks/quickbutik', (req, res) => {
console.log('Webhook received:', {
event_type: req.query.event_type,
order_id: req.query.order_id,
product_id: req.query.product_id,
timestamp: new Date().toISOString(),
ip: req.ip,
headers: req.headers
});
res.status(200).send('OK');
});
app.listen(3000, () => {
console.log('Webhook server listening on port 3000');
});
```
--------------------------------
### GET /orders
Source: https://quickbutik.dev/api-v1/quickstart-tutorial
Retrieves a list of orders. Supports query parameters for filtering and pagination.
```APIDOC
## GET /orders
### Description
Retrieves a list of orders. Supports query parameters for filtering and pagination.
### Method
GET
### Endpoint
/orders
### Query Parameters
- **limit** (integer) - Optional - The maximum number of orders to return.
- **offset** (integer) - Optional - The number of orders to skip before returning results.
- **status** (string) - Optional - Filter orders by their status (e.g., 'pending', 'shipped').
### Request Example
```http
GET /v1/orders?limit=10&status=pending
```
### Response
#### Success Response (200)
- **orders** (array) - An array of order objects.
- **order_id** (integer) - The unique identifier for the order.
- **customer_name** (string) - The name of the customer.
- **status** (string) - The current status of the order.
- **total_price** (number) - The total price of the order.
#### Response Example
```json
{
"orders": [
{
"order_id": 12345,
"customer_name": "John Doe",
"status": "pending",
"total_price": 99.99
},
{
"order_id": 12346,
"customer_name": "Jane Smith",
"status": "shipped",
"total_price": 45.50
}
]
}
```
```
--------------------------------
### Complete Category Template Example (Mustache)
Source: https://quickbutik.dev/theme-development/pages/category
This comprehensive Mustache template provides a full example of a category page structure, including breadcrumbs, category title, description1, and a section for additional information (description2). It serves as a blueprint for creating detailed category pages.
```mustache
{{category.name}}
{{#category.description1}}
{{&category.description1}}
{{/category.description1}}
{{#category.description2}}
{{#lang}}Additional Information{{/lang}}
{{&category.description2}}
{{/category.description2}}
```
--------------------------------
### GET /v1/orders
Source: https://quickbutik.dev/api-v1/quickstart-tutorial
Retrieves a list of recent orders. Supports filtering by limit and including detailed information.
```APIDOC
## GET /v1/orders
### Description
Retrieves a list of recent orders. Supports filtering by limit and including detailed information.
### Method
GET
### Endpoint
/v1/orders
### Query Parameters
- **limit** (integer) - Optional - The maximum number of orders to return.
- **include_details** (boolean) - Optional - Whether to include detailed information for each order.
### Request Example
```bash
curl "https://api.quickbutik.com/v1/orders?limit=5&include_details=true" \
-u your_api_key:your_api_key \
-H "Content-Type: application/json"
```
### Response
#### Success Response (200)
- **order_id** (string) - The unique identifier for the order.
- **date_created** (string) - The timestamp when the order was created.
- **total_amount** (string) - The total amount of the order.
- **status** (string) - The current status of the order.
#### Response Example
```json
[
{
"order_id": "12345",
"date_created": "2025-01-29 11:35:39",
"total_amount": "148.95",
"status": "1"
}
]
```
```
--------------------------------
### Basic Authentication - Header Example
Source: https://quickbutik.dev/api-v1/products/create-products
Provides an example of the 'Authorization' header format using Base64 encoded API key credentials for Basic Authentication.
```http
Authorization: Basic c2tfbGl2ZV9hYmMxMjM6c2tfbGl2ZV9hYmMxMjM=
```
--------------------------------
### Basic Authentication
Source: https://quickbutik.dev/api-v1/products/get-products
Explains how to use Basic Authentication with API Keys for authenticating requests to the Quickbutik API. It includes the format, encoding process, and a cURL example.
```APIDOC
## Basic Authentication
### Description
Details the process for authenticating API requests using Basic Authentication with API Keys. This method requires formatting your API key as credentials, Base64 encoding it, and including it in the `Authorization` header.
### Method
Basic Auth
### Security Scheme Details
- **Type**: `http`
- **Scheme**: `basic`
### How it works:
1. Format your credentials as `api_key:api_key` (using the SAME API key for both username and password).
2. Base64 encode the formatted string.
3. Include in the `Authorization` header as: `Authorization: Basic ENCODED_STRING`.
### Example:
- API Key: `sk_live_abc123`
- Formatted: `sk_live_abc123:sk_live_abc123`
- Base64 Encoded: `c2tfbGl2ZV9hYmMxMjM6c2tfbGl2ZV9hYmMxMjM=`
- Header: `Authorization: Basic c2tfbGl2ZV9hYmMxMjM6c2tfbGl2ZV9hYmMxMjM=`
### cURL Example:
```bash
curl https://api.quickbutik.com/v1/orders -u your_api_key:your_api_key
```
**Note**: All API requests must be made over HTTPS. Requests made over HTTP will be rejected. API keys can be generated in the Quickbutik Control Panel under Settings → API.
```
--------------------------------
### Authenticate and Fetch Product Count
Source: https://quickbutik.dev/api-v1/quickstart-tutorial
Demonstrates how to authenticate with the Quickbutik API using an API key and fetch the total product count. Includes examples for cURL, Node.js, and Python. Requires a Quickbutik store and API key.
```bash
# Replace 'your_api_key' with your actual API key
curl https://api.quickbutik.com/v1/products/count \
-u your_api_key:your_api_key \
-H "Content-Type: application/json"
```
```javascript
const fetch = require('node-fetch'); // or use built-in fetch in Node 18+
const apiKey = 'your_api_key';
const credentials = Buffer.from(`${apiKey}:${apiKey}`).toString('base64');
async function getProductCount() {
try {
const response = await fetch('https://api.quickbutik.com/v1/products/count', {
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
console.log('Product count:', data.count);
return data;
} catch (error) {
console.error('Error:', error.message);
}
}
getProductCount();
```
```python
import requests
import base64
import json
api_key = 'your_api_key'
credentials = base64.b64encode(f'{api_key}:{api_key}'.encode()).decode()
def get_product_count():
try:
response = requests.get(
'https://api.quickbutik.com/v1/products/count',
headers={
'Authorization': f'Basic {credentials}',
'Content-Type': 'application/json'
}
)
response.raise_for_status()
data = response.json()
print(f"Product count: {data['count']}")
return data
except requests.exceptions.RequestException as error:
print(f"Error: {error}")
get_product_count()
```
--------------------------------
### Fetch Product Count using cURL
Source: https://quickbutik.dev/api-v1/introduction
This snippet demonstrates how to fetch the total count of products in your Quickbutik store using a cURL command. It requires your API key for authentication and targets the '/products/count' endpoint. This is a basic example to test your API setup.
```bash
curl https://api.quickbutik.com/v1/products/count \
-u your_api_key:your_api_key
```
--------------------------------
### Example of Base64 Encoding for Authentication Header
Source: https://quickbutik.dev/api-v1/authentication
Illustrates the step-by-step process of creating the Authorization header value for Basic Authentication. It shows formatting the API key, base64 encoding it, and constructing the final header.
```text
sk_live_abc123:sk_live_abc123
```
```text
c2tfbGl2ZV9hYmMxMjM6c2tfbGl2ZV9hYmMxMjM=
```
```text
Authorization: Basic c2tfbGl2ZV9hYmMxMjM6c2tfbGl2ZV9hYmMxMjM=
```
--------------------------------
### Robust Production Webhook Server with Express (JavaScript)
Source: https://quickbutik.dev/webhooks/setup
An advanced Express.js webhook server for production. It includes security middleware (helmet, rate limiting), a health check endpoint, and asynchronous processing by queuing events. This setup enhances reliability and security.
```javascript
const express = require('express');
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');
const app = express();
// Security middleware
app.use(helmet());
// Rate limiting
const webhookLimiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1 minute
max: 100, // limit each IP to 100 requests per windowMs
message: 'Too many webhook requests from this IP',
standardHeaders: true,
legacyHeaders: false,
});
app.use('/webhooks', webhookLimiter);
// Health check endpoint
app.get('/health', (req, res) => {
res.status(200).json({
status: 'healthy',
timestamp: new Date().toISOString()
});
});
// Webhook endpoint
app.get('/webhooks/quickbutik', async (req, res) => {
const { event_type, order_id, product_id } = req.query;
// Log webhook receipt
console.log(`Webhook received: ${event_type}`, {
order_id,
product_id,
timestamp: new Date().toISOString(),
ip: req.ip
});
// Respond immediately
res.status(200).send('OK');
try {
// Add to processing queue
await addToQueue({
event_type,
order_id,
product_id,
received_at: new Date().toISOString()
});
} catch (error) {
console.error('Failed to queue webhook:', error);
// Send alert but don't fail the webhook response
await sendAlert({
type: 'webhook_queue_error',
event_type,
error: error.message
});
}
});
async function addToQueue(webhookData) {
// Add to Redis queue, SQS, or your preferred queue system
// This ensures webhook processing doesn't block the response
if (process.env.REDIS_URL) {
const redis = require('redis');
const client = redis.createClient({ url: process.env.REDIS_URL });
await client.lPush('webhook_queue', JSON.stringify(webhookData));
}
}
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Webhook server running on port ${PORT}`);
});
```
--------------------------------
### Example Success Response
Source: https://quickbutik.dev/api-v1/introduction
This JSON object represents a successful API response. It typically contains the requested data or a summary, such as the count of products. The structure is consistent across successful requests.
```json
{
"count": "42"
}
```
--------------------------------
### Dockerfile for Production Deployment (Dockerfile)
Source: https://quickbutik.dev/api-v1/guides/order-sync-tutorial
A Dockerfile to build a production-ready Node.js application. It sets up a working directory, installs production dependencies, copies application code, creates a non-root user for security, exposes port 3000, and includes a health check.
```dockerfile
FROM node:18-alpine
WORKDIR /app
# Copy package files
COPY package*.json ./
RUN npm ci --only=production
# Copy application code
COPY . .
# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
# Change ownership and switch to non-root user
RUN chown -R nodejs:nodejs /app
USER nodejs
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
CMD ["node", "server.js"]
```
--------------------------------
### Fetch and Sync Orders with Quickbutik API (Python)
Source: https://quickbutik.dev/api-v1/guides/order-sync-tutorial
This Python snippet shows how to fetch order details from Quickbutik and prepare them for synchronization. It uses asyncio and aiohttp for asynchronous operations and includes a retry mechanism for API calls, similar to the Node.js example.
```python
import asyncio
import aiohttp
import json
from typing import Dict, List, Optional
from quickbutik_api import QuickbutikAPI # From previous tutorial
class OrderSyncService:
def __init__(self, api_key: str):
self.api = QuickbutikAPI(api_key)
self.retry_attempts = 3
self.retry_delay = 1 # seconds
async def handle_new_order(self, order_id: str):
try:
# Fetch complete order details
orders = await self.retry_api_call(
lambda: self.api.get_orders(
order_id=order_id,
include_details=True,
apps_load=True
)
)
if not orders:
raise Exception(f'Order {order_id} not found')
order = orders[0]
```
--------------------------------
### Test Webhook Endpoint with Curl
Source: https://quickbutik.dev/webhooks/setup
A command-line utility to test if your webhook endpoint is publicly accessible and receiving requests. This helps in diagnosing connectivity issues and verifying the endpoint's basic functionality.
```bash
curl "https://your-domain.com/webhooks/quickbutik?event_type=test"
```
--------------------------------
### Example Error Response
Source: https://quickbutik.dev/api-v1/introduction
This JSON object illustrates an error response from the Quickbutik API. It includes an error code and a descriptive message, helping developers understand and resolve issues. This format is used for various error conditions.
```json
{
"code": 404,
"error": "Resource not found"
}
```
--------------------------------
### POST /v1/products
Source: https://quickbutik.dev/api-v1/products/create-products
This endpoint allows you to create new products and add them to your Quickbutik store. You can specify details like SKU, title, description, price, stock, and more.
```APIDOC
## POST /v1/products
### Description
Create and add products to store.
### Method
POST
### Endpoint
/v1/products
### Parameters
#### Request Body
- **sku** (string) - Optional - Article Number (SKU)
- **title** (string) - Required - Product title
- **description** (string) - Optional - Product description. Accepts HTML
- **price** (integer) - Optional - Price
- **before_price** (integer) - Optional - Compare price
- **purchase_price** (integer) - Optional - Purchase price (excl. vat)
- **tax_rate** (integer) - Optional - VAT percent (%)
- **weight** (number) - Optional - Weight (in grams)
- **stock** (integer) - Optional - Stock quantity
- **disable_minusqty** (string) - Optional - Stock: Disable minus quantity?
- **gtin** (string) - Optional - EAN-number / GTN (Global Trade Item Number)
- **headcategory_id** (integer) - Optional - Optional: Category id if a product should be placed into a specific category
- **headcategory_name** (string) - Optional - Optional: Category name if product should be placed into a new category
- **visible** (integer) - Optional - Visibility in store
- **images** (object) - Optional - Product images
- **metadata** (object) - Optional - Custom metadata for the product
- **permanent_redirect_from_url** (string) - Optional - URL to create a permanent redirect from (for SEO purposes)
- **skipIfDuplicate** (boolean) - Optional - Skip creation if product with same SKU already exists
- **variants** (object) - Optional - Product variants configuration
- **sync** (array) - Optional - Variants to sync (replaces all existing variants)
- **variant_option1_name** (string) - Required - First variant option name (e.g., Color, Size)
- **variant_option1_value** (string) - Required - First variant option value
- **variant_option2_name** (string) - Optional - Second variant option name
- **variant_option2_value** (string) - Optional - Second variant option value
### Request Example
```json
{
"sku": "T-SHIRT123",
"title": "My white tee!",
"description": "
",
"price": 299,
"before_price": 399,
"purchase_price": 69,
"tax_rate": 25,
"weight": 400,
"stock": 1,
"disable_minusqty": "1",
"gtin": "1234567890123",
"headcategory_id": 10,
"headcategory_name": "T-shirts",
"visible": 1,
"images": {},
"metadata": {
"key1": "value1"
},
"permanent_redirect_from_url": "http://example.com/old-product",
"created_at": "2023-01-01T12:00:00Z",
"updated_at": "2023-01-01T12:00:00Z"
}
```
```
--------------------------------
### Set Up Quickbutik Webhook Endpoint (Express.js & Flask)
Source: https://quickbutik.dev/api-v1/guides/order-sync-tutorial
This snippet demonstrates how to create a webhook endpoint to receive order notifications from Quickbutik. It includes immediate acknowledgment of the webhook and asynchronous processing of the order events. Ensure your endpoint responds within 10 seconds to prevent retries. Dependencies include Express.js for Node.js or Flask for Python.
```javascript
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Webhook endpoint for order notifications
app.post('/webhooks/quickbutik', async (req, res) => {
try {
const { event_type, order_id } = req.query;
console.log(`Received webhook: ${event_type} for order ${order_id}`);
// Acknowledge webhook immediately
res.status(200).send('OK');
// Process webhook asynchronously
await processOrderWebhook(event_type, order_id);
} catch (error) {
console.error('Webhook processing error:', error);
res.status(500).send('Error processing webhook');
}
});
async function processOrderWebhook(eventType, orderId) {
switch (eventType) {
case 'order.new':
await handleNewOrder(orderId);
break;
case 'order.done':
await handleOrderShipped(orderId);
break;
case 'order.cancelled':
await handleOrderCancelled(orderId);
break;
default:
console.log(`Unhandled event type: ${eventType}`);
}
}
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});
```
```python
from flask import Flask, request, jsonify
import asyncio
import logging
app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
@app.route('/webhooks/quickbutik', methods=['POST'])
def quickbutik_webhook():
try:
event_type = request.args.get('event_type')
order_id = request.args.get('order_id')
app.logger.info(f'Received webhook: {event_type} for order {order_id}')
# Acknowledge webhook immediately
response = jsonify({'status': 'received'})
# Process webhook asynchronously (in production, use a task queue)
asyncio.create_task(process_order_webhook(event_type, order_id))
return response, 200
except Exception as error:
app.logger.error(f'Webhook processing error: {error}')
return jsonify({'error': 'Error processing webhook'}), 500
async def process_order_webhook(event_type, order_id):
try:
if event_type == 'order.new':
await handle_new_order(order_id)
elif event_type == 'order.done':
await handle_order_shipped(order_id)
elif event_type == 'order.cancelled':
await handle_order_cancelled(order_id)
else:
app.logger.info(f'Unhandled event type: {event_type}')
except Exception as error:
app.logger.error(f'Error processing webhook: {error}')
if __name__ == '__main__':
app.run(debug=True, port=3000)
```
--------------------------------
### GET /v1/categories
Source: https://quickbutik.dev/api-v1/categories/get-categories
Fetch store categories. Optionally, filter by a specific category ID.
```APIDOC
## GET /v1/categories
### Description
Fetch store categories. Optionally, filter by a specific category ID.
### Method
GET
### Endpoint
/v1/categories
### Parameters
#### Query Parameters
- **category_id** (string) - Optional - Optional. Enter if you would like to fetch data from a specific category_id
### Request Example
(No request body for GET requests)
### Response
#### Success Response (200)
- **results** (Category) - Contains category information.
#### Response Example
{
"results": [
{
"category_id": 14,
"uri": "sulor",
"url": "/herr/skor/sulor",
"name": "Sulor",
"name_path": "Herr > Skor > Sulor",
"description1": null,
"description2": null,
"parent_id": 13
}
]
}
#### Error Response (401)
- **code** (integer) - Error code.
- **error** (string) - Error message.
#### Error Response Example
{
"code": 401,
"error": "Unauthorized - Invalid or missing authentication"
}
#### Error Response (404)
- **code** (integer) - Error code.
- **error** (string) - Error message.
#### Error Response Example
{
"code": 404,
"error": "Resource not found"
}
```
--------------------------------
### Fetch and Sync Orders with Quickbutik API (Node.js)
Source: https://quickbutik.dev/api-v1/guides/order-sync-tutorial
This Node.js snippet demonstrates how to fetch complete order details from Quickbutik, validate the data, and sync it to an external system. It includes a robust retry mechanism for API calls and handles potential synchronization failures.
```javascript
const QuickbutikAPI = require('./quickbutik-api'); // From our previous tutorial
class OrderSyncService {
constructor(apiKey) {
this.api = new QuickbutikAPI(apiKey);
this.retryAttempts = 3;
this.retryDelay = 1000; // 1 second
}
async handleNewOrder(orderId) {
try {
// Fetch complete order details
const orders = await this.retryAPICall(() =>
this.api.getOrders({
order_id: orderId,
include_details: true,
apps_load: true
})
);
if (!orders || orders.length === 0) {
throw new Error(`Order ${orderId} not found`);
}
const order = orders[0];
// Validate order data
if (!this.validateOrder(order)) {
throw new Error(`Invalid order data for order ${orderId}`);
}
// Sync to external system
await this.syncOrderToExternalSystem(order);
// Log success
console.log(`Successfully synced order ${orderId} to external system`);
} catch (error) {
console.error(`Failed to process new order ${orderId}:`, error);
// Add to retry queue or send alert
await this.handleOrderSyncFailure(orderId, error);
}
}
async retryAPICall(apiCall, attempt = 1) {
try {
return await apiCall();
} catch (error) {
if (attempt < this.retryAttempts) {
console.log(`API call failed, retrying in ${this.retryDelay}ms (attempt ${attempt}/${this.retryAttempts})`);
await new Promise(resolve => setTimeout(resolve, this.retryDelay * attempt));
return this.retryAPICall(apiCall, attempt + 1);
}
throw error;
}
}
validateOrder(order) {
return order.order_id &&
order.total_amount &&
order.customer &&
order.customer.email;
}
async syncOrderToExternalSystem(order) {
// Transform Quickbutik order to your system's format
const externalOrder = this.transformOrder(order);
// Make API call to your external system
const response = await fetch('https://your-system.com/api/orders', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.EXTERNAL_API_TOKEN}`
},
body: JSON.stringify(externalOrder)
});
if (!response.ok) {
throw new Error(`External API error: ${response.status} ${response.statusText}`);
}
return response.json();
}
transformOrder(quickbutikOrder) {
return {
external_order_id: quickbutikOrder.order_id,
customer_email: quickbutikOrder.customer.email,
total_amount: parseFloat(quickbutikOrder.total_amount),
currency: quickbutikOrder.payment?.currency || 'SEK',
items: quickbutikOrder.products?.map(product => ({
sku: product.sku,
quantity: product.qty || 1,
price: parseFloat(product.price || 0)
})) || [],
shipping_address: quickbutikOrder.customer.shipping_details,
billing_address: quickbutikOrder.customer.billing_details,
created_at: quickbutikOrder.date_created
};
}
async handleOrderSyncFailure(orderId, error) {
// In production, you might:
// 1. Add to a retry queue (Redis, SQS, etc.)
// 2. Send alerts to monitoring system
// 3. Log to error tracking service
console.error(`Order sync failed for ${orderId}:`, error.message);
// Example: Add to retry queue
// await this.addToRetryQueue({ orderId, error: error.message, timestamp: new Date() });
}
}
// Usage
const orderSync = new OrderSyncService(process.env.QUICKBUTIK_API_KEY);
async function handleNewOrder(orderId) {
await orderSync.handleNewOrder(orderId);
}
```
--------------------------------
### GET /v1/metadata/{scope}/{id}
Source: https://quickbutik.dev/api-v1/metadata/get-metadata
Retrieves metadata for a specified scope (order, product, or customer) and its corresponding ID.
```APIDOC
## GET /v1/metadata/{scope}/{id}
### Description
Retrieves metadata for a specified scope (order, product, or customer) and its corresponding ID.
### Method
GET
### Endpoint
/v1/metadata/{scope}/{id}
### Parameters
#### Path Parameters
- **scope** (string) - Required - Enum: order, product, customer. The scope for which to retrieve metadata.
- **id** (string) - Required - The ID of the selected scope. For example, when scope is 'product' and id is '1', metadata for product with ID '1' will be returned.
### Request Example
```json
{
"example": "Not applicable for GET requests"
}
```
### Response
#### Success Response (200)
- **additionalProperties** (object) - Key-value pairs of metadata.
- **type** (string) - The data type of the metadata value.
- **description** (string) - A description of the metadata value.
#### Response Example
```json
{
"example": "{\"meta_key_1\": \"meta_value_1\", \"meta_key_2\": \"meta_value_2\"}"
}
```
#### Error Responses
- **400** - Bad Request: Indicates an issue with the request parameters.
- **401** - Unauthorized: Indicates invalid or missing authentication credentials.
- **404** - Not Found: Indicates that the requested resource could not be found.
```
--------------------------------
### Mustache Variable Output Examples
Source: https://quickbutik.dev/theme-development/mustache-basics
Demonstrates basic variable output in Mustache templates, including product and store information. This is fundamental for displaying dynamic content on Quickbutik storefronts.
```mustache
{{product.title}}
Price: {{product.price}} {{product.currency}}
SKU: {{product.sku}}
```
--------------------------------
### Get Metadata by Scope and ID (OpenAPI)
Source: https://quickbutik.dev/api-v1/metadata/get-metadata
This OpenAPI specification defines the GET /v1/metadata/{scope}/{id} endpoint for retrieving metadata. It requires 'scope' (order, product, customer) and 'id' as path parameters. Successful requests return metadata in JSON format, while errors return standardized error responses.
```yaml
openapi: 3.1.0
info:
title: Quickbutik API
version: 1.0.0
description: >-
Use the Quickbutik API to access and manage stores, products, orders, and
more.
contact:
name: Quickbutik API Support
url: https://quickbutik.com/support
license:
name: Proprietary
x-fiddle-import-file: true
servers:
- url: https://api.quickbutik.com
description: Production server
security:
- BasicAuth: []
tags:
- name: Orders
description: Order management operations
- name: Products
description: Product catalog management
- name: Categories
description: Product category management
- name: Payment Methods
description: Available payment methods
- name: Shipping Methods
description: Available shipping methods
- name: Metadata
description: Custom metadata management
- name: Scripts
description: Storefront script management
paths:
/v1/metadata/{scope}/{id}:
get:
tags:
- Metadata
summary: Get metadata
description: Get metadata for selected scope and id
operationId: get-metadata
parameters:
- $ref: '#/components/parameters/MetadataScope'
- $ref: '#/components/parameters/MetadataId'
responses:
'200':
$ref: '#/components/responses/MetadataSuccess'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
components:
parameters:
MetadataScope:
name: scope
in: path
required: true
schema:
type: string
enum:
- order
- product
- customer
description: order|product|customer
MetadataId:
name: id
in: path
required: true
schema:
type: string
description: >-
Id of the selected scope. E.g when scope is product and id is 1,
metadata for product with id 1 will be returned
responses:
MetadataSuccess:
description: Metadata retrieved successfully
content:
application/json:
schema:
type: object
additionalProperties:
type: string
description: Key-value pairs of metadata
BadRequest:
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Unauthorized - Invalid or missing authentication
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
schemas:
Error:
type: object
properties:
code:
type: integer
example: 404
error:
type: string
example: Resource not found
securitySchemes:
BasicAuth:
type: http
scheme: basic
description: >
**Basic Authentication with API Keys**
The Quickbutik API uses Basic Authentication where you use your API key
as both the username and password.
**How it works:**
1. Format your credentials as `api_key:api_key` (using the SAME API key
for both username and password)
2. Base64 encode the formatted string
3. Include in the Authorization header as: `Authorization: Basic
ENCODED_STRING`
**Example:**
- API Key: `sk_live_abc123`
- Formatted: `sk_live_abc123:sk_live_abc123`
- Base64 Encoded: `c2tfbGl2ZV9hYmMxMjM6c2tfbGl2ZV9hYmMxMjM=`
- Header: `Authorization: Basic
c2tfbGl2ZV9hYmMxMjM6c2tfbGl2ZV9hYmMxMjM=`
**cURL Example:**
```bash
curl https://api.quickbutik.com/v1/orders -u your_api_key:your_api_key
```
All API requests must be made over HTTPS. Requests made over HTTP will
be rejected.
API keys can be generated in the Quickbutik Control Panel under Settings
→ API.
```
--------------------------------
### Generic Static Page Example (Mustache)
Source: https://quickbutik.dev/theme-development/pages/static
A comprehensive HTML template for rendering generic static pages. It includes basic SEO meta tags, header, main content area with breadcrumbs, and a footer. This template uses Mustache for dynamic content.
```mustache
{{page.title}} - {{shop.name}}