Integration API Reference
The Integration API allows you to effortlessly connect your app with Fabrixa, enabling you to export orders and track their production and fulfillment status.
The base URL for accessing the Integration API is:
https://api.fabrixa.com/v2/integration
Ensure that all requests are made to this base URL, followed by the specific endpoint path you wish to access. This base URL is the foundation for interacting with the Fabrixa API, enabling the retrieval, creation, updating, or deletion of resources.
Authentication
To access the Integration API, you'll need to authenticate your requests using both an Application Access Token and an Application Key. These should be provided as follows:
Authorization Header:
Authorization: Bearer APPLICATION_ACCESS_TOKEN
Application Key Header:
X-Application-Key: APPLICATION_KEY
Example cURL Command:
curl -X 'GET' \
'https://api.fabrixa.com/v2/integration/ping' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer APPLICATION_ACCESS_TOKEN' \
-H 'X-Application-Key: APPLICATION_KEY'
Replace APPLICATION_ACCESS_TOKEN with your actual access token and
APPLICATION_KEY with your actual application key.
Endpoints and Requests
The Integration API endpoints are organized by resource type and follow the RESTful architectural style. Each endpoint represents a resource, and actions on these resources are performed using standard HTTP methods.
All Integration API requests and responses are in JSON format, providing a consistent and easy-to-use interface for interacting with the API.
For comprehensive details about all Integration API endpoints, including examples of requests and responses, please refer to our Swagger documentation.
Response Format:
All endpoints return data in a standardized format. This format includes the following objects:{
"links": {
"self": "https://api.fabrixa.com/v2/integration/products",
"first_page": "https://api.fabrixa.com/v2/integration/products?page=1",
"last_page": "https://api.fabrixa.com/v2/integration/products?page=2",
"next_page": "https://api.fabrixa.com/v2/integration/products?page=2",
"prev_page": null
},
"meta": {
"total": 2,
"current_page": 1,
"per_page": 10
},
"data": [
{
"id": 1,
"name": "Product 1",
"description": "Description of Product 1"
},
{
"id": 2,
"name": "Product 2",
"description": "Description of Product 2"
}
]
}
Description of Response Objects:
links
Contains pagination links to navigate through the results.
self: The URL of the current page.first_page: The URL of the first page of results.last_page: The URL of the last page of results.next_page: The URL of the next page of results. Null if there is no next page.prev_page: The URL of the previous page of results. Null if there is no previous page.
meta
Contains metadata about the response, such as pagination information.
total: The total number of items available across all pages.current_page: The current page number of the results.per_page: The number of items per page.
data
The main content of the response. The data object will vary depending on the
endpoint. It can be a single object (e.g., details of one product) or an array of objects (e.g.,
a list of products).
Status and Error Codes
All API requests return HTTP status codes that provide insight into the response.
400 Bad Request
The server cannot process the request due to validation errors. This status code is returned when the request fails validation, such as missing or invalid parameters.
401 Unauthorized
The client has not provided valid authentication credentials. This error also occurs when the access token has been revoked.
403 Forbidden
The server has denied the request due to insufficient access rights, typically caused by incorrect or missing access permissions.
404 Not Found
The requested resource could not be found on the server.
429 Too Many Requests
The client has exceeded the allowable number of requests in a given timeframe. Please refer to the Rate Limits section for more information.
5xx Errors
An internal server error has occurred. Please contact Fabrixa support and provide details of the failed request.
Error Response Body
Here is an example of an error response body:
{
"links": {
"self": "https://api.fabrixa.com/v2/integration/ping"
},
"meta": [],
"errors": {
"messages": [
"Application Key is not specified."
]
}
}
errors: Contains details about the errors encountered. The messages array lists
the error messages that describe what went wrong. In the case of a Bad Request, you will receive the
names of the fields with the failed validation.
Rate Limits
The Integration API supports a limit of 30 requests per application per minute.
If you exceed these limits, you will receive a 429 Too Many Requests response.
All Integration API responses include the X-RateLimit-Remaining header, which shows how many
requests the client can make, and the X-RateLimit-Limit header with the total number
allowed per minute.
Orders
Creating an Order
To create an order via the Fabrixa Integration API, send a POST request to the /v2/integration/orders
endpoint. The request body should include the following details:
Request Body Structure
number(optional): The order number. If not provided, a unique number will be generated.comments(optional): Any additional comments or notes related to the order.purchased_at: The date and time when the order was purchased, formatted asYYYY-MM-DD HH:MM:SS.client_ip(optional): The IP address of the customer.client_user_agent(optional): The user agent string of the customer.rows: An array of order items, each containing the following fields:variant_id: The ID of the product variant (for details on how to get product and variants, see Swagger documentation).quantity: The quantity of the product variant ordered.client_barcode(optional): The unique identifier provided by the client for each order line/item. This barcode, formatted asCode 128, is used for tracking and managing orders on the client’s side.cart_item_key(required without sources): A unique identifier generated by the platform embedding the Fabrixa Design Widget, used to track the customization for a specific product in the cart. This key must be included in the order creation request to associate the saved customization with the order.sources(required without cart_item_key): An array of source files (prints) associated with the product, each containing:type: The type of the product, e.g., "duvet", "pillow", "print" etc (depends on the product type).url: The URL of the source file.properties(optional): Additional properties for the source image, such as:fill_style: The style of filling the image over the printing file, e.g., "contain" or "pattern".width(optional): The width of the pattern image in mm.height(optional): The height of the pattern image in mm.
customer: The customer's details, including:first_name: The customer's first name.last_name: The customer's last name.email: The customer's email address.phone: The customer's phone number.
shipping_address: The shipping address for the order, including:address: The first line of the address.address2(optional): The second line of the address.address3(optional): The third line of the address.city: The city of the address.country_code: The country code of the address inISO 3166-2format.country: The country of the address.postal_code: The postal code of the address.state(optional): The state or region of the address.first_name: The recipient's first name.last_name: The recipient's last name.phone(optional): The recipient's phone number.company(optional): The company name, if applicable.
shipping_label(optional): The shipping label details, including:method_name: The shipping method name, e.g., "Post NL".tracking_number: The tracking number of the shipment.tracking_url: The URL for tracking the shipment.label_pdf_url: The URL of the PDF version of the shipping label.date_created: The date and time when the label was created, formatted asYYYY-MM-DD HH:MM:SS.
Sample Request
{
"number": "NL2024010201",
"comments": "Customer agrees with a low resolution file.",
"purchased_at": "2024-06-26 21:12:22",
"client_ip": "127.0.0.1",
"client_user_agent": "Mozilla",
"rows": [
{
"variant_id": 2705,
"quantity": 1,
"client_barcode": "1234567890",
"sources": [
{
"type": "duvet",
"url": "https://samples-files.com/samples/Images/tiff/480-360-sample.tiff",
"properties": {
"fill_style": "contain"
}
},
{
"type": "pillow",
"url": "https://samples-files.com/samples/Images/tiff/480-360-sample.tiff",
"properties": {
"fill_style": "pattern",
"width": 100,
"height": 100
}
}
]
}
],
"customer": {
"first_name": "John",
"last_name": "Doe",
"email": "3VJtP@example.com",
"phone": "0647185332"
},
"shipping_address": {
"address": "Pierre cuypershof",
"address2": "17",
"city": "Amsterdam",
"country_code": "NL",
"country": "Netherlands",
"postal_code": "1012 AB",
"state": "North Holland",
"first_name": "John",
"last_name": "Doe",
"phone": "0647185332"
},
"shipping_label": {
"method_name": "Post NL",
"tracking_number": "3SYZXG1585577",
"tracking_url": "https://postnl.nl/tracktrace/3SYZXG1585577",
"label_pdf_url": "https://api.fabrixa.com/storage/8966630826422f36d822f91680012141.pdf",
"date_created": "2024-01-01 00:00:00"
}
}
Source Files
When including source files in your order, ensure that they meet the following requirements:
type
The type field specifies the type of the product that the source file represents.
Possible values include "duvet", "pillow", "print", etc.
It is crucial to ensure that the type value aligns with the
available_source_types of the product variant. Additionally, the
variant model contains a required_source_types field, which is an
array of mandatory types that must be provided during order creation. Failing to include
these required types may result in production errors.
When providing a PDF file as a source, you can include multiple product layers as separate pages within a single PDF document. Each page will be interpreted as a distinct layer during processing. This allows you to send complex multi-layer designs as a single source entry in your API request.
The type in the source object must be set to "file" when you provide
a multi-layer PDF. The system will automatically process each page as a separate product layer.
⚠️ Important: Ensure that each page in the PDF has the correct dimensions corresponding to the respective product layer. Mismatched page sizes may result in scaling or alignment issues during production.
"sources": [
{
"type": "file",
"url": "https://samples-files.com/samples/source.pdf",
"properties": {
"fill_style": "contain"
}
}
]
For further details, see the Swagger documentation.
url
The url field in the request should contain a direct link to the source file.
Ensure that the
URL is accessible and that the file can be downloaded without authentication. Additionally, the
link must remain accessible throughout the production process to ensure successful order
completion.
Source files should be provided in a supported format such as JPEG,
PNG, TIFF or PDF.
Ensure that the images are high-quality and suitable for printing.
The maximum dimensions for each source image are 15,000 pixels on either side.
Images exceeding this limit may be resized or rejected. Additionally, ensure that the image
resolution matches the product dimensions; otherwise, the image may be resized or cropped to fit
the product size.
There is no specific resolution requirement. Ensure that the image quality is sufficient for printing.
Color Space
Images should be in RGB color space to ensure accurate color representation. If an
image is in a different color space, it will be converted during processing, which may result in
incorrect colors.
Each source file should not exceed 50 MB in size. Larger files may be
rejected or cause delays in processing.
properties
The properties field allows you to specify additional details for the source file,
such as how it should be applied to the product. Common properties include:
fill_style: Defines how the image should be placed on the product. Options include "contain" (fit within the product area) or "pattern" (repeat the image to cover the entire area).width(optional): Specifies the width of the pattern image in millimeters when using the "pattern" fill style.height(optional): Specifies the height of the pattern image in millimeters when using the "pattern" fill style.
Ensure that the properties are set according to the requirements of the product and its variant. Incorrect or missing properties may result in improper rendering of the source image on the product.
Fulfillment Status
To get the fulfillment status for a specific order, send a GET request to the /orders/{order_id}/fulfillments
endpoint. This will provide a list of fulfillments associated with the order, including each item's
status, product details, and the progress of production steps.
Sample Response
{
"data": [
{
"id": 1499,
"barcode": "1200004169200",
"status": "unfulfilled",
"created_at": "2024-08-19T12:38:59.000000Z",
"updated_at": "2024-08-19T12:39:00.000000Z",
"variant": {
"id": 32327,
"name": "Test iAPI blanket product",
"subtitle": "100 x 150 cm",
"SKU": "COF099191"
},
"product": {
"id": 1306,
"name": "Test iAPI blanket product",
"subtitle": "Test iAPI blanket product"
},
"production_steps": [
{
"id": 5,
"name": "Print duvet",
"description": "Printing the duvet according to the specified design and dimensions.",
"status": {
"value": "pending",
"notes": null,
"updated_at": null
}
},
{
"id": 6,
"name": "Print pillow",
"description": "Printing the pillow cover with the assigned design.",
"status": {
"value": "pending",
"notes": null,
"updated_at": null
}
},
// More production steps...
]
}
]
}
The response includes a list of fulfillments, each providing the following details:
id: A unique identifier for the fulfillment.barcode: A barcode associated with the fulfillment, used for internal tracking and identification, also can be printed on the product.status: The current fulfillment status, which can be unfulfilled or fulfilled, indicating whether the fulfillment has been completed.created_atandupdated_at: Timestamps indicating when the fulfillment was created and last updated.variant: An object containing detailed information about the product variant, such as the name, subtitle, and SKU.product: An object with details about the product, including its name and subtitle.production_steps: An array of production steps, each detailing a specific stage in the production process. The list of the steps depend on the product type. For each step:id: A unique identifier for the production step.name: The name of the production step (e.g., "Print duvet").description: A brief description of what the production step entails.status: An object representing the current status of the step, which can be:- pending: The step has not yet started.
- in progress: The step is currently underway.
- rejected: The step encountered an issue and was not completed successfully.
- done: The step has been completed.
notes: Any additional notes related to the step.updated_at: The last time the status of the production step was updated.
Each fulfillment record corresponds to a specific product or product variant within the order, and each copy of the product in the order will have its own fulfillment record. This ensures that every item is tracked individually throughout the production process.
If no fulfillments are returned for an order, it indicates that the order has not yet entered the processing stage.
Fabrixa Design Widget
The Fabrixa Design Widget is a tool that allows users to seamlessly customize and personalize products in real-time with an intuitive interface where users can create or upload their own designs.
This widget is ideal for businesses that offer custom products, enabling customers to visualize their designs before finalizing orders.
Embedding the Widget
You can embed the Fabrixa Design Widget into your website using an iframe. This enables your
customers to personalize products directly on your site during the checkout process.
Example iframe for embedding the widget:
<iframe id="fabrixa-design-widget"
src="https://widget.fabrixa.com?application_key={application_key}&product_id={product_id}&product_variant_id={product_variant_id}&cart_item_key={cart_item_key}"
name="FabrixaDesignWidget"
scrolling="no"
frameborder="1"
width="100%"
height="100%"
allowfullscreen="">
</iframe>
Be sure to replace the values for product_id, product_variant_id, cart_item_key,
and application_key with your dynamic values.
application_key: A unique key used for authentication to the Integration API.product_id: The ID of the product, which can be retrieved from the Integration API.product_variant_id: The ID of the product variant, which can also be obtained from the Integration API.cart_item_key: A unique value generated by the platform embedding the iframe to identify the cart item associated with the product. This key is used to save the user's customizations, and during the order creation via Integration API, it helps identify the saved customizations and assign them to the order. See example bellow.
Request to Create an Order with cart_item_key:
{
"number": "NL2024010201",
"purchased_at": "2024-06-26 21:12:22",
"client_ip": "127.0.0.1",
"client_user_agent": "Mozilla",
"rows": [
{
"variant_id": 2705,
"quantity": 1,
"cart_item_key": "0cb76770-de2d-4524-aa48-47b6e5f0d8a5",
}
],
"customer": {
...
},
"shipping_address": {
...
},
"shipping_label": {
...
}
}
Widget Events
When the Add to Cart button is clicked inside the iframe, the following command is executed:
window.parent.postMessage('customizationFinished', '*');
Similarly, when the Back button is clicked, this command is executed:
window.parent.postMessage('closeButtonClicked', '*');
The postMessage method facilitates cross-origin communication between the iframe and its
parent window, allowing it to send messages that notify the parent about specific user actions.
The first argument of postMessage is the data you want to send. In this case, the string
'customizationFinished' indicates that the user has finalized their customization and is
adding the product to the cart. The string 'closeButtonClicked' indicates that the user has
chosen to go back.
In the parent window, you can listen for these messages using the message event listener.
Here’s how to handle both messages:
window.addEventListener('message', function(event) {
if (event.origin === 'https://widget.fabrixa.com') {
if (event.data === 'customizationFinished') {
// Handle the Add to Cart event
console.log('Customization finished and item can be added to cart.');
} else if (event.data === 'closeButtonClicked') {
// Handle the Back button event
console.log('Back button clicked.');
}
}
});
In this listener, you check the origin of the incoming message to ensure it comes from a trusted source (the iframe). Depending on the message received, you can perform the necessary actions, such as updating the user interface or processing the cart.
Validating the origin of the message is crucial for security, as it helps prevent
unauthorized scripts from interacting with your application.
Customization Preview
After the customization is completed, you can display the final design using the preview URL below. This URL returns an image of the customized product, which can be used as the src value in an <img> tag.
It's ideal for showing the customized product in your cart, order summary, or anywhere else in your shop interface.
https://api.fabrixa.com/v2/shop/integration/product-customizations/{CART_ITEM_KEY}/preview?Application-Key={APPLICATION_KEY}
Replace {CART_ITEM_KEY} with the actual cart item key, and
{APPLICATION_KEY} with your valid application key.
Example usage in an image tag:
<img
src="https://api.fabrixa.com/v2/shop/integration/product-customizations/{CART_ITEM_KEY}/preview?Application-Key={APPLICATION_KEY}"
alt="Customized Product Preview"
style="max-width: 100%; height: auto;" />
Live Demo
To make this demo work, you need to retrieve the product_id and
product_variant_id of an available product using the Integration API and utilize them with
your Application Key.
Webhooks
Webhooks are used by Fabrixa to notify your system about real-time events like order updates or creations. When an event occurs, Fabrixa sends a webhook to your server containing relevant information.
Your server must expose a public POST endpoint to handle incoming webhooks.
Webhook Headers
The webhook request includes the following headers to help you identify and validate the incoming request:
{
"content-type": "application/json",
"x-webhook-signature": "YmEwNjBhMGMyMzE3ZWQ5NGQ5NDYwOGVhNzNhMjQ4M2MyODZkZmI3NTQ1YzYxYjdkMzNhZjgzYzBmMTkxYTAxMw==",
"x-webhook-topic": "order.updated",
}
Header Breakdown
content-type– Always set toapplication/jsonfor webhooks.x-webhook-signature– The HMAC-SHA256 signature for request verification (explained below).x-webhook-topic– The event type or topic of the webhook. For example:order.created– Triggered when a new order is created.order.updated– Triggered when an existing order is updated.
Webhook Event Types
Fabrixa webhooks notify your system of changes in order status or activity. Each webhook is triggered by a specific x-webhook-topic value. Below are the currently supported topics:
| Topic | Description |
|---|---|
order.created |
Triggered when a new order is placed in Fabrixa, either via API request or directly in the platform. |
order.updated |
Triggered when order details such as the order status or fulfillment status are updated. |
Order Statuses
- Completed – Order has been shipped or picked up, and receipt is confirmed. For digital products, the client has paid, and files are available for download.
- Canceled – Customer canceled payment and the transaction was not completed.
- On hold – The order is temporarily blocked.
- Imported – The order was imported into the platform.
Fulfillment Statuses
- Unfulfilled – The order has not been prepared or sent out yet.
- Partially fulfilled – Some items in the order have been processed or shipped, while others are still pending.
- Scheduled – Order is planned and scheduled for processing.
- Rejected – The fulfillment request has been declined, often due to invalid order details or unavailability.
- Fulfilled – The order has been completely processed and delivered or made available to the customer.
Example Payload
Below is an example of the payload that will be sent with the webhook. This payload represents an order update:
{
"id": 23069,
"number": "1250211835",
"comments": null,
"is_archived": false,
"status": "imported",
"fulfillment_status": "unfulfilled",
"purchased_at": "2025-04-17T16:17:21.000000Z",
"created_at": "2025-04-17T16:17:23.000000Z",
"updated_at": "2025-04-18T07:43:52.000000Z",
"rows": [
{
"id": 27954,
"quantity": 1,
"client_barcode": "1250211835",
"fulfillment_status": "unfulfilled",
"variant": {
"id": 293457,
"name": "Sherpa fleece deken",
"subtitle": "100x150",
"SKU": "SFD787231",
"product": {
"id": 5319,
"name": "Sherpa fleece deken",
"subtitle": "Sherpa fleece deken"
}
},
"sources": [
{
"type": "print",
"url": "https://storage.googleapis.com/fabrixa-api/storage/99b10aaa-df4d-47e4-9bc9-b1d6a785df4c/orders/merchandise-sources/120002795400.pdf",
"properties": {
"fill_style": "contain"
}
}
]
}
]
}
Verifying the Signature
To ensure the webhook request is authentic and untampered, verify the x-webhook-signature header. This involves recalculating the HMAC-SHA256 signature using the raw request payload and your secret key, then comparing it to the received signature.
🔧 Raw PHP Example
$payload = file_get_contents('php://input');
$yourSecret = 'your-secret-key';
$expectedSignature = base64_encode(hash_hmac('sha256', $payload, $yourSecret, true));
$receivedSignature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
if (!hash_equals($expectedSignature, $receivedSignature)) {
http_response_code(403);
exit('Invalid signature');
}
🚀 Laravel Example
public function handle(Request $request)
{
$yourSecret = 'your-secret-key';
$payload = $request->getContent();
$expectedSignature = base64_encode(hash_hmac('sha256', $payload, $yourSecret, true));
$receivedSignature = $request->header('x-webhook-signature');
if (!hash_equals($expectedSignature, $receivedSignature)) {
abort(403, 'Invalid signature');
}
// Continue processing...
}
Replace $yourSecret with your shared secret key. Always use hash_equals for comparing signatures to mitigate timing attacks.
Retry Mechanism
Webhooks are disabled after 10 unsuccessful delivery attempts by default. If your endpoint returns an unsuccessful status such as 404 or any 5xx error, the webhook will retry for a total of 10 times. If the webhook continues to return a non-2xx or non-3xx response code, it will be deactivated. Successful responses include:
2xx– Indicates successful processing (e.g.,200 OK)301and302– Redirection responses indicating the webhook has been successfully handled or forwarded.
Response
It is strongly recommended that your endpoint returns a 200 OK status code as quickly as possible to acknowledge the successful receipt of the webhook. While any 2xx or 3xx response is considered successful, 200 is the most commonly used and reliable.
To avoid delivery timeouts or retries, it's best to immediately return 200 OK and handle the processing of the webhook payload asynchronously (e.g., by dispatching a background job or pushing to a queue). If your endpoint takes too long to respond, it may be considered a failure even if the response is ultimately successful.
Responses with status codes in the 4xx or 5xx range, or timeouts, will trigger retries according to the retry mechanism.