Prerequisites: You’ll need a Quickbutik store and an API key. If you don’t have an API key yet, generate one in your store’s Control Panel under Settings → API.
What we’ll build
By the end of this tutorial, you’ll have a simple integration that:- ✅ Authenticates with the Quickbutik API
- ✅ Fetches your store’s product count
- ✅ Retrieves your latest orders
- ✅ Handles errors gracefully
Step 1: Set up authentication
First, let’s test your API connection with a simple request to count your products:# 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"
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();
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()
Expected Response
{
"count": "42"
}
Troubleshooting authentication
Troubleshooting authentication
Common issues:
- 401 Unauthorized: Check that your API key is correct
- Invalid base64: Ensure you’re encoding
api_key:api_keyformat - SSL errors: Make sure you’re using
https://nothttp://
echo -n "your_api_key:your_api_key" | base64
Step 2: Fetch your latest orders
Now let’s retrieve your most recent orders:curl "https://api.quickbutik.com/v1/orders?limit=5&include_details=true" \
-u your_api_key:your_api_key \
-H "Content-Type: application/json"
async function getLatestOrders() {
try {
const response = await fetch('https://api.quickbutik.com/v1/orders?limit=5&include_details=true', {
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const orders = await response.json();
console.log(`Found ${orders.length} recent orders`);
orders.forEach(order => {
console.log(`Order #${order.order_id}: ${order.total_amount} (${order.status})`);
});
return orders;
} catch (error) {
console.error('Error fetching orders:', error.message);
}
}
getLatestOrders();
def get_latest_orders():
try:
response = requests.get(
'https://api.quickbutik.com/v1/orders',
params={'limit': 5, 'include_details': True},
headers={
'Authorization': f'Basic {credentials}',
'Content-Type': 'application/json'
}
)
response.raise_for_status()
orders = response.json()
print(f"Found {len(orders)} recent orders")
for order in orders:
print(f"Order #{order['order_id']}: {order['total_amount']} ({order['status']})")
return orders
except requests.exceptions.RequestException as error:
print(f"Error fetching orders: {error}")
get_latest_orders()
Expected Response
[
{
"order_id": "12345",
"date_created": "2025-01-29 11:35:39",
"total_amount": "148.95",
"status": "1"
}
]
Step 3: Update an order status
Let’s mark an order as “done” (shipped):curl -X PUT https://api.quickbutik.com/v1/orders \
-u your_api_key:your_api_key \
-H "Content-Type: application/json" \
-d '[{
"order_id": "12345",
"status": "done",
"shipping_info": {
"trackingnumber": "1Z999AA1234567890",
"company": "UPS"
},
"email_confirmation": "true"
}]'
async function markOrderAsShipped(orderId, trackingNumber) {
try {
const response = await fetch('https://api.quickbutik.com/v1/orders', {
method: 'PUT',
headers: {
'Authorization': `Basic ${credentials}`,
'Content-Type': 'application/json'
},
body: JSON.stringify([{
order_id: orderId,
status: 'done',
shipping_info: {
trackingnumber: trackingNumber,
company: 'UPS'
},
email_confirmation: 'true'
}])
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const result = await response.json();
console.log('Order updated successfully:', result);
return result;
} catch (error) {
console.error('Error updating order:', error.message);
}
}
markOrderAsShipped('12345', '1Z999AA1234567890');
def mark_order_as_shipped(order_id, tracking_number):
try:
response = requests.put(
'https://api.quickbutik.com/v1/orders',
headers={
'Authorization': f'Basic {credentials}',
'Content-Type': 'application/json'
},
json=[{
'order_id': order_id,
'status': 'done',
'shipping_info': {
'trackingnumber': tracking_number,
'company': 'UPS'
},
'email_confirmation': 'true'
}]
)
response.raise_for_status()
result = response.json()
print('Order updated successfully:', result)
return result
except requests.exceptions.RequestException as error:
print(f"Error updating order: {error}")
mark_order_as_shipped('12345', '1Z999AA1234567890')
Step 4: Handle errors like a pro
Here’s how to build robust error handling:class QuickbutikAPI {
constructor(apiKey) {
this.apiKey = apiKey;
this.credentials = Buffer.from(`${apiKey}:${apiKey}`).toString('base64');
this.baseUrl = 'https://api.quickbutik.com/v1';
}
async request(endpoint, options = {}) {
const url = `${this.baseUrl}${endpoint}`;
try {
const response = await fetch(url, {
...options,
headers: {
'Authorization': `Basic ${this.credentials}`,
'Content-Type': 'application/json',
...options.headers
}
});
// Handle different HTTP status codes
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
switch (response.status) {
case 401:
throw new Error('Authentication failed. Check your API key.');
case 404:
throw new Error(`Resource not found: ${errorData.error || 'Unknown error'}`);
case 400:
throw new Error(`Bad request: ${errorData.error || 'Invalid data provided'}`);
case 500:
throw new Error('Server error. Please try again later.');
default:
throw new Error(`HTTP ${response.status}: ${errorData.error || response.statusText}`);
}
}
return await response.json();
} catch (error) {
if (error.name === 'TypeError' && error.message.includes('fetch')) {
throw new Error('Network error. Check your internet connection.');
}
throw error;
}
}
async getOrders(params = {}) {
const queryString = new URLSearchParams(params).toString();
const endpoint = queryString ? `/orders?${queryString}` : '/orders';
return this.request(endpoint);
}
async updateOrderStatus(updates) {
return this.request('/orders', {
method: 'PUT',
body: JSON.stringify(Array.isArray(updates) ? updates : [updates])
});
}
}
// Usage
const api = new QuickbutikAPI('your_api_key');
async function example() {
try {
const orders = await api.getOrders({ limit: 5 });
console.log('Orders fetched successfully:', orders.length);
} catch (error) {
console.error('Failed to fetch orders:', error.message);
}
}
import requests
import base64
from typing import Dict, List, Optional
class QuickbutikAPI:
def __init__(self, api_key: str):
self.api_key = api_key
self.credentials = base64.b64encode(f'{api_key}:{api_key}'.encode()).decode()
self.base_url = 'https://api.quickbutik.com/v1'
def _request(self, endpoint: str, method: str = 'GET', data: Optional[Dict] = None):
url = f'{self.base_url}{endpoint}'
headers = {
'Authorization': f'Basic {self.credentials}',
'Content-Type': 'application/json'
}
try:
response = requests.request(method, url, headers=headers, json=data)
# Handle different HTTP status codes
if response.status_code == 401:
raise Exception('Authentication failed. Check your API key.')
elif response.status_code == 404:
error_data = response.json() if response.content else {}
raise Exception(f"Resource not found: {error_data.get('error', 'Unknown error')}")
elif response.status_code == 400:
error_data = response.json() if response.content else {}
raise Exception(f"Bad request: {error_data.get('error', 'Invalid data provided')}")
elif response.status_code == 500:
raise Exception('Server error. Please try again later.')
response.raise_for_status()
return response.json()
except requests.exceptions.ConnectionError:
raise Exception('Network error. Check your internet connection.')
except requests.exceptions.Timeout:
raise Exception('Request timed out. Please try again.')
except requests.exceptions.RequestException as e:
raise Exception(f'Request failed: {str(e)}')
def get_orders(self, **params) -> List[Dict]:
endpoint = '/orders'
if params:
query_string = '&'.join([f'{k}={v}' for k, v in params.items()])
endpoint += f'?{query_string}'
return self._request(endpoint)
def update_order_status(self, updates) -> Dict:
if not isinstance(updates, list):
updates = [updates]
return self._request('/orders', method='PUT', data=updates)
# Usage
api = QuickbutikAPI('your_api_key')
try:
orders = api.get_orders(limit=5)
print(f'Orders fetched successfully: {len(orders)}')
except Exception as error:
print(f'Failed to fetch orders: {error}')
🎉 Congratulations!
You’ve successfully built your first Quickbutik integration! You now know how to:- ✅ Authenticate with the API
- ✅ Fetch orders and products
- ✅ Update order statuses
- ✅ Handle errors gracefully
Next steps
Set up webhooks
Get real-time notifications when orders are created or updated
Order sync tutorial
Learn how to build a complete order synchronization system
Need help?
Get Support
Stuck on something? We’re here to help! Reach out to support@quickbutik.com with your questions.