NAV Navbar
php shell
  • Custom Gateway Personalisation Platform APIs
  • For Retailers
  • For Suppliers
  • GraphQL
  • Custom Gateway Personalisation Platform APIs


    This document describes some of the APIs that the personalisation platform exposes.

    Which APIs you might be interested in depend on whether you are a retailer or a supplier.

    Please select from the left hand side.

    Our IP Range

    Our IP range is listed below if you would like to or need to white list us.

    For Retailers


    This guide covers how to integrate your website into the Custom Gateway personalisation platform.

    The guide is split into two key sections.


    The Smartlink guide covers how to integrate personalisation apps into your website.

    You might not need to follow this part depending on your requirements.


    The Order-iT guide covers how you can send orders to Custom Gateway's Order Manager System, from where the orders will be routed to the correct supplier.

    You will definitely need to follow this part.

    Virtual Product Creator

    The Virtual Product Creator (VPC) guide shows how you can embed Custom Gateway's VPC tool into your website. The VPC allows your end users to create their own sellable product designs within the platform without ever leaving your site.

    You might not need to follow this part depending on your requirements.

    Before Starting

    Before starting either section, you will need the following information:

    Both will be provided to you by Custom Gateway. Please contact us for more details.

    The VPC tool has additional requirements that are documented in the VPC section.

    Note on Code Samples

    The shell code samples to the right assume that you have access to the curl command line tool.

    Custom Gateway's personalisation apps are provided in the form of a URL which can be embedded via an iframe into your website.

    Different apps exist and you may require different URL parameters depending on your use case.

    The below URL is a bare bones example of our standard offering:

    The URL can be broken down into a few key parts:

    Part Description
    acp3_2 The app that you would like to use
    en_GB The app locale
    default The app configuration
    p=1007644 The ID of the product to load
    r=2d-canvas The renderer to use. Typically this would either be 2d-canvas for 2D products or webgl for 3D products. multi can be used to load both renderers however doing so may slightly reduce loading speeds
    guid Your unique company reference ID

    Adding to Cart

    <!DOCTYPE html>
            <iframe style="border: 1px solid red; width: 100%; height: 50px;" src="" id="app"></iframe>
            let iframeOrigin = "";
            let iframeUrl = iframeOrigin + "/s/app/acp3_2/en_GB/default.html#p=1007644&r=2d-canvas&guid=COMPANYREFID&a2c=postMessage";
            let meo = location.origin;
            let mei = Math.random().toString(16).substr(2);
            window.addEventListener("message", e => {
                if(e.origin == iframeOrigin && == mei) {
                    switch( {
                        case 'ADD_TO_CART_CALLBACK':
                            var printJobRef =[0].ref;
            let iframe = document.getElementById('app');
            iframe.src = iframeUrl + "&meo=" + meo + "&mei=" + mei;

    When a user clicks on an "Add to Cart" button within a personalisation app, the app will create a "print job" which represents the user's design.

    Subsequently, the app will then use the postMessage API to send an ADD_TO_CART_CALLBACK event to the parent window.

    You will need to add a JavaScript message handler to the parent window that listens for the ADD_TO_CART_CALLBACK event. The handler should add the item to the user's shopping cart and store the value of the printJobRef field.

    For the postMessage API to function, 3 Smartlink iframe URL parameters are required.

    Name Description
    meo The origin of the parent window (i.e
    mei A random string.
    a2c Should always be set to postMessage

    The meo and mei URL parameters are used to ensure that the parent window only acts on messages from the correct iframe instance. The app will not send messages if either meo and mei are not specified. For security reasons it is also important to ensure that the message is from the origin.

    The event's data contains a separate item for each print job that was created. Usually, each item would be added to the cart separately however you may wish to consolidate them depending on your exact use case.

    Each item element of the data property contains the below fields.

    Name Type Description
    ref string The unique reference code for the created print job.
    sku string The product's SKU. This should only be needed if the smartlink contains a product selector. In single product mode, your event handler should already know which product to add to cart.
    thumbnails array A collection of thumbnails for different views of the product (including the user's design)

    Restoring a User's Design

    If you wish to allow the user to edit their design later on, it can be loaded again by passing the value of printJobRef back to the personalisation app via the pj (print job) URL parameter.

    For example:

    When the user clicks "Add to Cart" again in the app, the ADD_TO_CART_CALLBACK event will be called as normal but with a new value for printJobRef.


    A user can save their design, allowing them to reload it at a later date. You need to provide a callback URL which the user is redirected to after saving. The callback URL allows you to record the information needed to reload the user's design.

    The following URL enables the save button:

    Handling The Callback

    Once the user has clicked save, the app will make a application/x-www-form-urlencoded form POST to your callback URL.

    The POST will include a data field, the value of which is a JSON encoded object.

      "created_from": "",
      "ref": "44EEEA752F59C3A3B1",
      "thumbnails": [
          "name": "thumbnail",
          "url": "",
          "description": ""
          "name": "thumbnail_60",
          "url": "",
          "description": ""

    The object will contain many fields, the most important of which are:

    Name Type Description
    created_from string The original app URL
    ref string A unique reference code needed to reload the user's design
    thumbnails array A collection of thumbnails for the user's design which you might like to display somewhere

    Reloading The Saved Design

    The user's design can subsequently be loaded by taking the value of the created_from field and appending &ps= and the value of the ref field. For example:


    postMessage API

    In addition to the ADD_TO_CART_CALLBACK event, Smartlinks also emit other events.


    window.addEventListener("message", e => {
        if(e.origin == iframeOrigin && == mei) {
            switch( {
                case 'IFRAME_RESIZE':
           = + "px";

    The IFRAME_RESIZE event can be used to automatically resize the iframe on your site so that all content fits within it without the need for scroll bars within the iframe.


    The Order-iT API has a single endpoint:

    Rate Limiting

    Requests to the API are rate limited to 1000 requests per hour and 10000 requests per day.

    A 400 HTTP status code will be returned in the event of the limit being exceeded, please check the error code table for more details.

    If you need this limit to be increased on a per account basis, please contact us.

    IP Restrictions

    For additional security, an IP white list can be enabled for your company reference ID.

    Any requests made using your company reference ID and API key from an IP address that isn't white listed will be rejected.

    Please contact us to set up IP restrictions, quoting the IP addresses that you will be sending requests from.

    Migrating from 2.1

    This document refers to the 2.2 version of the API.

    The endpoints for version 2.1 are or

    Version 2.2 is mostly backwards compatible with 2.1 however there are some key differences:


    curl ""
      -H "Authorization: Basic COMPANYREFID:APIKEY"

    Make sure to replace COMPANYREFID and APIKEY with your company reference ID and API key respectively.

    If authentication fails, the following JSON response body will be returned, along with a 400 HTTP status code:

        "error": {
            "message": "Authentication failed",
            "code": 50000

    To authenticate against the API, include the Authorization HTTP header with every request.

    For example,

    Authorization: Basic COMPANYREFID:APIKEY

    Submitting an Order

        -H "Content-Type: application/json"\
        -H "Authorization: Basic COMPANYREFID:APIKEY"\
        "external_ref": "TEST001",
        "sale_datetime": "2017-01-01 12:00:43",
        "shipping_company": "Custom Gateway Ltd."
        "shipping_address_1": "Pinewood Court",
        "shipping_postcode": "SK10 2XR",
        "shipping_country_code": "GB",
        "items": [
                "external_ref": "ITEM001",
                "quantity": 1,
                "type": 2,
                "print_job_ref": "CF921CF10F59B3A258"

    A successful request will result in an array of orders being returned:

            "id": "...",
            "ref": "...",
            "external_ref": "TEST001",
            "has_error": false,
            "error_message": "",
            "items": [
                    "id": "...",
                    "ref": "...",
                    "external_ref": "ITEM001"

    Please see the errors section for more information on the has_error and error_message fields.

    An order can be created by sending a JSON encoded order object via a POST request to the API.

    HTTP Request


    Order Object

    Name Type Description
    external_ref string A unique reference code that can be used to identify the order in your system.
    company_ref_id integer A unique company ID (supplied by Custom Gateway). Must correspond to the API key provided via the URL.
    sale_datetime string The date and time (must be UTC) of when the order was placed in the format YYYY-MM-DD HH:MM:SS (i.e. 2013-08-07 10:54:23)
    required_dispatch_date string The required dispatch date for the order in the format YYYY-MM-DD (i.e. 2013-08-07)
    customer_name string Customer's full name.
    customer_email string Customer's contact email.
    customer_telephone string Customer's contact telephone number.
    shipping_company string Shipping address company.
    shipping_address_1 string Shipping address 1.
    shipping_address_2 string Shipping address 2.
    shipping_address_3 string Shipping address 3.
    shipping_address_4 string Shipping town or city.
    shipping_address_5 string Shipping region.
    shipping_postcode string Shipping post or ZIP code.
    shipping_country_code string ISO 3166-1 alpha-2 country code.
    shipping_method string Shipping method.
    shipping_carrier string Shipping carrier.
    shipping_note_url string An optional URL for a specifying an external shipping note. If no value is provided then a basic shipping note will be generated. The URL must begin with either http:// or https://.
    billing_customer_name string Billing name.
    billing_company string Billing address company.
    billing_address_1 string Billing address 1.
    billing_address_2 string Billing address 2.
    billing_address_3 string Billing address 3.
    billing_address_4 string Billing town or city.
    billing_address_5 string Billing region.
    billing_postcode string Billing post or ZIP code.
    coupon_code string Coupon code.
    payment_trans_id string Payment transaction identifier.
    status_callback_url string Order status callback URL.
    items array An array of order items

    Item Object

    Name Type Description
    external_ref string A reference code that can be used to identify the order item in your system.
    sku string Product SKU.
    description string Product description.
    quantity integer Item quantity.
    colour string Item colour.
    size string Item size.
    textual_product_id integer Determines which CPP product the order item is for (can be used for either textual items or external URL items).
    type integer Item type code
    external_url string Required for external items (type 1). URL to an image which will be used for this item. This URL must be available until the order has been processed.
    external_thumbnail_url string Required for external items (type 1). URL to a thumbnail of an image which will be used for this item. This URL must be available until the order has been processed.
    print_job_ref string Required for print job items (type 2). A unique identifier linking this item to an already existing print job (created by the Custom Gateway product designer). The specified print job must have been created using a company ID which the current API key (URL parameter k) is permitted access to.
    print_on_demand_ref string Required for print on demand items (type 3). A unique identifier linking this item to a pre-created Print-on-Demand sample (created from within the Custom Gateway ACP).
    external_urls array of ExternalUrl Required for external URL (multi) items (type 7). An array of ExternalUrl objects.

    ExternalUrl Object

    Name Type Description
    fullsize string A public URL to fullsized print ready artwork.
    thumbnail string A public URL to a thumbnail of the artwork.
    name string Position name, i.e. Front or Back. The give name must correlate a print area name set in CPP

    Item Type Codes

    Type Code Name Description
    1 External URL an item for which the artwork is specified as an external URL (not hosted by Custom Gateway).
    2 Print Job An item that can be associated with a print job created by the Custom Gateway product designer. Once an order has been created, any referenced print jobs will be set to "Paid" in the "Print Manager".
    3 Print-on-Demand An item that can be associated to a precreated Print-on-Demand sample.
    4 Stock Item A item that does not have any generated artwork.
    5 Textual Item An item that does not have artwork generated by Custom Gateway but does have textual personalisation.
    7 External URL [Multi] Identical to the External URL type but allows for multiple images to be provided.

    Status Callbacks

    Example callback URL request body

        "id": "...",
        "external_ref": "...",
        "ref": "...",
        "status": "...",
        "status_name": "...",
        "shipping_tracking": "...",
        "shipping_method": "...",
        "shipping_carrier": "..."

    Every time an order's status changes in OMS, the URL that you specified in the status_callback_url field will be sent a PUT request with a JSON encoded request body.

    Your status callback should return a 200 HTTP response code if successful. In the event of a 4XX or 5XX error response code, OMS will keep retrying the request up to a maximum of 5 times at 2 hour intervals. For statuses that you are not interested in, please be sure to still reply with a 200 response code to prevent unnecessary retries.

    Request Fields

    Name Type Description
    id integer The unique sequential ID for the order
    external_ref string The order reference number provided when creating the order
    ref string The unique alphanumeric reference code for the order
    status int The order's current status
    status_name string The name of the order's current status
    shipping_tracking string A shipment tracking ID. This field may be blank and its population is dependent on the product supplier.
    shipping_method string The shipping method that will be used for shipping the order
    shipping_carrier string The shipping carrier that will be used for shipping the order

    The shipping_carrier and shipping_method values may be different to what was specified during order creation. It is common for the values of both fields to mapped to different but equivalent values that the supplier is able to accept.

    For example, if Standard Delivery Next Day is specified as the shipping_method during order creation, it may be mapped to Royal Mail and RM1 for shipping_carrier and shipping_method by the supplier.


    Generally your status callback would not need to handle all possible order statuses.

    Status Code Status Name Description
    0 Unknown The status of the order is unknown.
    1† Received The order has been received by Custom Gateway.
    2 Unused Unused
    4 In Production (Only when batching is enabled) At least a part of the order has been downloaded by a fulfilment operative.
    8† Dispatched The order has been fully dispatched.
    32 QC Query The order has a QC query against it.
    64 Dispatched (Retailer Notified) Dispatch confirmation has been explicitly pushed to the retailer by Custom Gateway.
    128 Cancelled The order has been cancelled.
    256 On Hold The order is on hold.
    512 Sent to Supplier The order has been routed to an appropriate supplier.
    513 Received by Supplier The order has been confirmed as received by an appropriate supplier.
    515 Sent to Shipper The order details have been sent to a shipment courier (such as UPS or DPD).
    516† Received by Shipper The order details have been confirmed by a shipment courier.


    API Errors

    An example HTTP 400 error response body

        "error": {
            "code": 12345,
            "message": "A brief description of the problem"

    An example HTTP 500 error response body

        "error": {
            "code": null,
            "message": "An unexpected error occured 84C1E94BAF83D9C2A43CFCCBC04FE937"

    When the API encounters an error, it will return either a 400 or 500 HTTP status code along with a JSON encoded error response.

    The 500 HTTP status code indicates an internal error that should be reported to us. Please quote the full error message, including the long alphanumeric identifier.

    The JSON encoded error response will contain both an error code and a message.

    Error Code Meaning Solution
    0 Please check the error message for more details
    100 Invalid JSON Please check the error message for details on syntax errors etc.
    8000 No items At least one order item must be specified
    8001 An order already exists with the specified value for external_ref Ensure that external_ref is unique for each order
    8011 Invalid sale_datetime sale_datetime must be in the correct format and not in the future.
    8012 Invalid status_callback_url status_callback_url must be a valid URL and have a public DNS entry
    8013 Invalid country code shipping_country_code must be valid 2 character ISO 3166-1 alpha-2 country codes
    8014 Invalid required_dispatch_date required_dispatch_date must be in the correct format and not in the past.
    8030 Order company_ref_id not specified
    8031 Order external_ref not specified
    8032 Order shipping_address_1 not specified
    8033 Order shipping_postcode not specified
    8034 Order shipping_country_code not specified
    8040 Invalid item type
    8041 Invalid item quantity quantity must be greater than 0
    8042 Invalid item attribute for a textual item The attribute must exist as an image or text area on the specified product
    8043 Invalid item print job The print_job_ref field must be valid and be a print job that is owned by your account
    8050 Item external_ref not specified
    8051 Item print_job_ref not specified
    8052 Item textual_product_id not specified
    8053 Item external_url not specified
    8054 Item external_thumbnail_url not specified
    50000 Either your company reference ID or API key are incorrect Please make sure your details are correct
    50001 Your company type does not allow receiving orders Please contact support
    50002 Your company has been deactivated
    50003 The IP address used to send the request does not appear in the IP white list
    50004 The rate limit has been exceeded

    Administrative Errors

    An example response for when an order is created in an error state

            "id": "...",
            "external_ref": "TEST001",
            "has_error": true,
            "error_message": "Failed to split order due to invalid supplier information",
            "items": [
                    "id": "...",

    In certain circumstances, the API might return a success response code but create an order that is in an error state.

    Such error states can be dealt with by non-technical staff and do not represent issues with how the API has been used.

    One example scenario could be if the API is unable to correctly determine the supplier of an order line due to a misconfigured product in CPP.

    When an administrative error occurs, the order fields has_error and error_message will be populated with true and an error message respectively. The order status will also be set to QC Query.

    Virtual Product Creator

    Before embedding the VPC tool into your website, you need the following pieces of information:

    Additionally, it is also necessary to specify two product category IDs:

    Please contact us for more details.

    Embedding the VPC

    $params = [
        'company_ref_id' => 99999,
        'approved_pc' => 1,
        'blanks_pc' => 2,
        'time' => time(),
        'nonce' => bin2hex(random_bytes(8)),
        'origin' => "{$_SERVER['REQUEST_SCHEME']}://{$_SERVER['HTTP_HOST']}",
    $query = http_build_query($params);
    $params += [
        'hmac' => hash_hmac('sha512', $query, $apiKey)
    $query = http_build_query($params);
    $iframeUrl = "{$query}";

    The VPC tool can be embedded into your site using an iframe set to the following URL:

    Several query parameters are also required:

    Name Description Required?
    company_ref_id Your unique company reference ID Yes
    approved_pc The ID of the CPP product category into which all created content is inserted Yes
    blanks_pc The ID of the CPP product category containing available product blanks Yes
    time The number of seconds since the UNIX epoch Yes
    nonce A random alphanumeric string that should be different each time you load the VPC Yes
    origin The origin of the page loading the VPC Yes
    hmac A HMAC message digest Yes

    Calculating the HMAC Message Digest

    Due to the nature of the VPC tool, it is necessary for the personalisation platform to be able to verify that your site is who it says it is. This is accomplished via the use of the HMAC algorithm.

    The input to the HMAC algorithm should be the query part of your iframe URL (minus the hmac parameter itself) whilst the HMAC secret key is your API key. sha512 should be selected as the hashing algorithm.

    The time query parameter is used to ensure that any HMAC value older than 15 seconds is rejected. This means that it is important that your server has the correct date and time set.

    For example, given the following query parameters:

    Name Value
    company_ref_id 99999
    approved_pc 1
    blanks_pc 2
    time 1543581543
    nonce randomstring

    the HMAC input data would be:


    which gives the below message digest when using AAAAAAAAAAAAAAAAAAAAAAAAAAA as the HMAC secret key:


    resulting in the final iframe URL:

    Product Creation Callback

    <!DOCTYPE html>
                html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; }
                iframe { width: 100%; height: 100%; border: 0; }
            window.addEventListener('message', function(e) {
                if( == 'PRODUCTS_CREATED' && e.source == document.getElementById('iframe').contentWindow) {
                    let products =;
                    // Do something to create the products within your own eCommerce
                    // platform
            <iframe id="iframe" src=""></iframe>

    Once the end user has created their products using the VPC tool, a PRODUCTS_CREATED message will be passed back to the parent site using the postMessage API.

    Your site can listen for such messages using Javascript.

    When the message is received, your site should use the data provided within the message to create relevant products in the most appropriate way for your particular eCommerce package.

    After creating the products, the VPC iframe should be closed and the user redirected to an appropriate landing page.

    The body field of the message will be an array containing an element for each product that the user selected.

    Each element has the following fields:

    Name Description
    id The CPP product ID that can be used in a Smartlink to reload the user's design
    description The design description entered by the user.
    name The design name entered by the user.
    retail_sku A unique SKU generated by the VPC tool using the product's supplier SKU as a base
    snapshots.small A 600x600 preview of the user's product
    base_product.productCode The SKU to use when sending future order lines for the product.

    For Suppliers


    This guide covers only some of the various ways in which suppliers who don't wish to use OMS can still integrate with the platform.

    Generic FileSystem Integration

    The Generic FileSystem integration is a simple way of receiving order details from the platform.

    Typically order details are represented by an XML file however we can support other formats on request.

    Files can be transferred to a supplier use several different protocols such as FTP, SFTP, FTPS and S3.

    Order API

    The order API (coming soon) allows suppliers to programmatically retrieve new orders from the platform via an API.

    Order Shipping API

    The order shipping API allows suppliers to make use of the platform's various shipping integrations to create shipments with providers such as Hermes and Royal Mail.

    When a shipment is created, a shipping label will be returned.

    Before Starting

    For both APIs, you will need the following information:

    Both will be provided to you by Custom Gateway. Please contact us for more details.

    Note on Code Samples

    The shell code samples to the right assume that you have access to the curl command line tool.

    Order Push API


        "id": 0,
        "ref": "unique Custom Gateway reference"
        "external_ref": "retailer order reference",
        "customer_name": "",
        "shipping_address_1": "",
        "shipping_address_2": "",
        "shipping_address_3": "",
        "shipping_address_4": "",
        "shipping_address_5": "",
        "shipping_postcode": "",
        "shipping_country_code": "",
        "shipping_carrier": "",
        "shipping_method": "",
        "items": [
                "id": 0,
                "type": 1,
                "mapped_sku": "supplier SKU",
                "sku": "retail SKU",
                "description": "Product description",
                "quantity": 1,
                "assets": [
                        "name": "output-1.png",
                        "url": "",
                        "description": "Front"

    The Order Push API allows a supplier to configure a per dropship URL that will receive order details for any new orders created by retailers.

    Order details are sent to the URL via a simple JSON POST request.

    Additionally, a X-CustomGateway-Hmac header is also sent as part of the request. This header can be used to verify that the request has originated from Custom Gateway.


    To receive order pushes, a supplier must enable the "Generic API" supplier integration against the relevant dropshipping account in OMS.

    Once the integration has been enabled, a push URL defined and changes saved, a HMAC key will be automatically generated.

    Verifying the HMAC Header

    Whilst optional, this step is highly recommended for security.

    For each push request, a HMAC message digest can be calculated using the SHA256 algorithm with the request body as the input and the HMAC key displayed in the Generic API settings page.

    The calculated HMAC message digest should match the value of the requests's X-CustomGateway-Hmac header.

    If the values do not match then you should reject the push request.

    Verifying the HMAC header

    $hmac = hash_hmac('sha256', file_get_contents('php://stdin'), $key);
    if(!hash_equals($hmac, getHeader('X-CustomGateway-Hmac')))
        throw new \Exception('HMAC mismatch');

    Order Shipping API

    Before Starting

    Using the order shipping API requires a shipping integration to have been enabled on your relevant dropshipping accounts within the personalisation platform.

    Please contact us for more details.

    Shipping an Order

        -H "Authorization: Basic COMPANYREFID:APIKEY" -X POST

    A successful request will result in an array of shipments being returned:

            "id": 1234567890,
            "carrier": "hermes",
            "tracking": "ABCDEFGHIJKL",
            "label_url": "",
            "items": [
                    "id": 1234,
                    "order_id": 1234,
                    "quantity": 10,
                    "quantity_shipped": 10

    A order can be shipped by making a simple POST request to the order shipment endpoint.


    The shipping service used is automatically determined based on how your account (and possibly the retailers account) have been configured.

    A successful request will result in one or more shipment entities being created and returned.

    If an order has been split into multiple shipments, then the items collection on each shipment can be used to identify which items are included in that particular shipment.

    Stock API


    The stock API allows a supplier to update available stock levels for their products.

    Updating Stock Levels

    $guzzle = new \GuzzleHttp\Client;
    $guzzle->request("PUT", "", [
        'headers' => [
            'Authorization' => "Basic COMPANYREFID:APIKEY"
        'json' => [
                "sku" => "ABC",
                "data" => [
                    "quantity_available" => 10
                "sku" => "DEF",
                "data" => [
                    "quantity_available" => 12
        -H "Authorization: Basic COMPANYREFID:APIKEY" -X PUT\
        -d'[ { "sku": "ABC", "data":  { "quantity_available": 10 } }, { "sku": "DEF", "data": { "quantity_available": 12 } } ]'

    Updates to stock levels can be made by issuing a PUT request to the availability endpoint:


    The body of the PUT request should be a JSON encoded array, with a single element for each stock product to be updated.


    This section assumes a basic understanding of GraphQL and that the reader understands how to consume GraphQL APIs from their language of choice.

    More info on GraphQL can be found here


    $client = new \GuzzleHttp\Client;
    $clientId = ...;
    $clientSecret = ...;
    $scopes = [ ... ];
    $response = $client->post("", [
        "form_params" => [
            "client_id"     => $clientId,
            "client_secret" => $clientSecret,
            "grant_type"    => "client_credentials"
            "scope"         => implode(' ', $scopes)
    $json = (string)$response->getBody();
    $accessToken = json_decode($json, true)['access_token'];
    curl ""\
        -F "client_id=CLIENTID"\
        -F "client_secret=CLIENTSECRET"\
        -F "grant_type=client_credentials"\
        -F "scope=SCOPES"

    A successful request will return an access token.


    To use the GraphQL API, it is first necessary to obtain OAuth access tokens using your client ID and client secret.

    This can be done by making a POST request to the OAuth access token endpoint:

    On success, the request will result in a JSON encoded object that contains an access_token field.

    The access token is valid for 3600 seconds and must be provided via the Authorization header in subsequent API calls.

    Product Manager

    The product manager GraphQL API is located at:


    Example mutation

    mutation($baseProducts: [ID]!, $categoryId: ID!, $artwork: [CreateVirtualProductsFromArtworkArtwork]!) {
        createVirtualProductsFromArtwork(baseProducts: $baseProducts, categoryId: $categoryId, artwork: $artwork) {
    $client = new \GuzzleHttp\Client;
    $response = $client->post("", [
        "headers" => [
            "Authorization" => "Bearer {$accessToken}"
        "json" => [
            "query" => 'mutation($baseProducts: [ID]!, $categoryId: ID!, $artwork: [CreateVirtualProductsFromArtworkArtwork]!) {
                            createVirtualProductsFromArtwork(baseProducts: $baseProducts, categoryId: $categoryId, artwork: $artwork) {
            "variables" => [
                "baseProducts" => [ $productId1, $productId2, ... ],
                "categoryId" => $categoryId,
                "artwork" => [
                        "design_name": "Design #001",
                        "urls" => [
                                "preview" => "",
                                "original" => ""
    $json = (string)$response->getBody();
    $virtualProductIds = json_decode($json)['data']['createVirtualProductsFromArtwork'];

    Virtual products can be created via the createVirtualProductsFromArtwork GraphQL mutation, which accepts three mandatory variables.

    Required scopes:

    Variable Type Description
    baseProducts [ID]! A collection of base product IDs.
    categoryId ID! The ID of the target product category into which the new virtuals will be created.
    artwork CreateVirtualProductsFromArtworkArtwork A collection of artwork objects.

    Each artwork object has a:
    • design name
    • preview URL (used in live preview smartlinks)
    • full size URL (using for artwork generation)

    A new virtual product is created for each product specified via the baseProducts variable.

    Storing Images

    curl -X POST ""
    $client = new \GuzzleHttp\Client;
    $response = $client->post("", [
        'query' => [
            'url' => ''

    On success, a simple JSON response will be returned:

      "urls": {
        "original": "",
        "preview": "",
        "processed": ""

    It is possible to use Custom Gateway to host your images using the User Image API.

    The API is able to download an image from a URL, generate a live preview image automatically and store both.

    The URLs can then be used in the createVirtualProductsFromArtwork API call.