Back to Website
Show / Hide Table of Contents

State files

  • 18 minutes to read

Each time you invoke Editor.saveProduct() or Editor.finishProductDesign(), the Design Editor generates a state file that captures all objects loaded in the editor. The key difference is that Editor.finishProductDesign() also renders the product and generates URLs that link to hi-res outputs and proof images. By default, these state files are stored in the ..\userdata\<someUserId>\states\ folder for a single user and they are retained indefinitely until manually deleted. The Design Editor does not automatically clean up these files. At the same time, you can use the Web API to manage state files within your application, allowing you to list available state files, delete them, reload images in state files from their original sources, and more.

This API works based on HTTPS requests and is handled by the StateFiles controller with the following methods:

Function Request type URL
Get a list of user's state files GET ~/api/users/{userId}/states?page=number&items=number&extendedStateInfo=boolean
Check if a state file is available HEAD ~/api/users/{userId}/states/{stateId}
Upload a state file POST ~/api/users/{userId}/states/{stateId}
Download a user's state file GET ~/api/users/{userId}/states/{stateId}
Delete a user's state file DELETE ~/api/users/{userId}/states/{stateId}
Copy and clone a state file POST ~/api/users/{userId}/states/{stateId}
Modify a state file PATCH ~/api/users/{userId}/states/{stateId}
Get product tags from a state file GET ~/api/users/{userId}/states/{stateId}/tags
Get variable items from a state file GET ~/api/users/{userId}/states/{stateId}/variables
Get the entire object model from a state file GET ~/api/users/{userId}/states/{stateId}/model

When you need to enable common storage of state files for a load-balanced environment, refer to Load-balanced environment and learn how to use symlinks to work with state files in this case.

To optimize storage when working with large designs and reusing graphics, you may want to enable the space-saving mode. However, this will require copying the cache folder with images during backup procedures or migration to another Design Editor instance.

You can also organize external storage for state files based on webhooks. Later in this topic, we will describe this aproach.

When you need to patch images in user's state files, you can use the UserImages controller, which allows for downloading packed images from a state file and upload them back to your server.

URL Parameters

The StateFiles controller requires the following parameters:

  • userId=[string] - a user identifier.
  • stateId=[string] - a file name of a state without an extension.
Warning

For the master user, this API only allows you to read state files and copy them from other users.

You can also pass the following optional parameters when getting a list of state files:

  • page=[number] is the number of the page to output. The default value is null.
  • items=[number] defines the number of items per page. The default value is null.
  • extendedStateInfo=[boolean] enables the output of such additional parameters as the surface count and product tags. If false, outputs only state IDs and timestamps. The default value is true.

When you pass both page and items, then the response headers will contain the number of TotalPages and TotalItems.

Error Response

This controller can return the following errors:

  •   Status Code: 403 Forbidden
      Content: HTTPS Required
    
  •   Status Code: 403 Forbidden
      Content: Invalid Security Key
    
  •   Status Code: 404 Not Found
      Content: The specified state file cannot be found.
    
  •   Status Code: 400 Bad Request
      Content: This state already exists.
    
  •   Status Code: 500 Internal Server Error
      Content: The remote server returned an error: (404) Not Found.
    

It is recommended to download the code sample written in ECMAScript 2015 that demonstrates how you can work with the API and refer to this sample when reading this topic.

Important

The security model of Design Editor requires you to pass X-CustomersCanvasAPIKey in request headers. The snippets below define the API security key in JavaScript code. It could be highly insecure if it runs on a public site. However, you can use it this way in your admin panel, or just for demonstration purposes.

Getting a List of a User's State Files

To get a list of state files, you can make the following request. If a user has many state files, it will display only the first 10 of them.

Request Example

const userId = "default";
const url = `https://localhost:44300/api/users/${userId}/states?page=1&items=10`;
fetch(url).then(response => {
    return response.json();
}).then(json => {
    for (let i = 0; i < json.length; i++) {
        const s = json[i];
        console.log(s.stateId);
    }
});

Success Response

For example, you will get the following response to this request when the default user has a state file.

Status Code: 200 OK
TotalPages: 1
TotalItems: 1
Content:
[{
  "stateId":"0777bb82-6f89-4e72-93b1-aad1b875602b",
  "dateModified":"5/26/2020 8:29",
  "surfaceCount":2,
  "tag":null
}]

Checking If a User's State File is Available

To check if a user's folder contains a state file, you can make the following request.

Request Example

var userId = "JohnWood";
var stateId = "1f190673-226d-4c31-87b4-0140805cc445";
var url = `https://localhost:44300/api/users/${userId}/states/${stateId}`;

fetch(url, {
    method: "HEAD",
    headers: {
        "X-CustomersCanvasAPIKey": "UniqueSecurityKey"
    }
}).then(async function (response) {
    if (response.ok) {
        console.log("OK");
    }
    else {
        console.log("Not Found");
    }
});

Success Response

When the state file is in the user's folder, this controller returns:

Status Code: 200 OK

Uploading a State File

This method accepts a state file in the request payload and uploads this file to the ..\userdata\{userId}\states\ folder. When you pass the stateId parameter in your request, this identifier is assigned to the uploaded state file. When you omit stateId, this controller generates a new unique identifier and returns it in the response.

Request Example

const userId = "JohnWood";
var formData = new FormData(document.querySelector("#state_to_upload"))

fetch("https://localhost:44300/api/users/${userId}/states/", {
    method: "POST",
    headers: {
        "X-CustomersCanvasAPIKey": "UniqueSecurityKey"
    },
    body: formData
})
.then(
    response => {
        console.log(response);
    }
);

Success Response

When the state file has been successfully uploaded, this controller returns an ID of this state:

Status Code: 200 OK
Content: "d1ba8901-5884-4a2c-8e28-1463b6862fa9"

Downloading a User's State File

Request Example

const userId = "JohnWood";
const stateId = "1f190673-226d-4c31-87b4-0140805cc445";
const url = `https://localhost:44300/api/users/${userId}/states/${stateId}`;
logElement.textContent = "init request";

fetch(url, {
    method: "GET",
    headers: {
        "X-CustomersCanvasAPIKey": "UniqueSecurityKey",
        'Accept': 'application/json',
        "Content-Type": "application/json"
    }
})
.then(
    response => {
        if (response.ok) {
            console.log("The state file was downloaded successfully.");
            console.log(response.url);
        }
        else
            console.error("Failed to download the state file.");
    },
    e => console.error("Failed to download the state file.")
);

Success Response

If the result is successful, this API returns a file stream:

Status Code: 200 OK
Content-type: application/octet-stream

Deleting a User's State File

To delete a saved product from the userdata folder, you can make the following request.

Request Example

const userId = "JohnWood";
const stateId = "1f190673-226d-4c31-87b4-0140805cc445";
const url = `https://localhost:44300/api/users/${userId}/states/${stateId}`;
fetch(url, {
        method: "DELETE",
        headers: {
            "X-CustomersCanvasAPIKey": "UniqueSecurityKey",
            "Content-Type": "application/json"
        }
    })
    .then(
        response => { return response.json(); },
        e => console.log("Failed to delete the state file.")
    )
    .then(json => {
        if (json === true)
            console.log("The state file was deleted successfully.");
        else if (json === false)
            console.log("Requested state file is not found.");
    });

Success Response

If the result is successful, this API can return the following:

  • The state file was not found.

    Status Code: 200 OK
    Content: false
    
  • The state file was deleted successfully.

    Status Code: 200 OK
    Content: true
    

Copy and Clone a State File

Request Payload

To copy state files, you need to pass the following parameters in the request body:

  • UserId=[string] - an identifier of the user whose file you want to copy.
  • StateId=[string] - an identifier of the state file you want to copy.
  • Overwrite=[boolean] - allows for overwriting state files.
const parameters = {
    "CopyFrom": {
        "UserId": "sourceUserId",
        "StateId": "sourceStateId"
    },
    "Overwrite": true
};

Note that userId and stateId in the request URL are the destination identifiers.

Request Example

const userId = "JohnWood";
const stateId = "Invitation";
const sourceUserId = "masteruser";
const sourceStateId = "1f190673-226d-4c31-87b4-0140805cc445";
const url = `https://localhost:44300/api/users/${userId}/states/${stateId}`;
const parameters = {
    "CopyFrom": {
        "UserId": sourceUserId,
        "StateId": sourceStateId
    },
    "Overwrite": true
};
fetch(url, {
        method: "POST",
        headers: {
            "X-CustomersCanvasAPIKey": "UniqueSecurityKey",
            "Accept": "application/json",
            "Content-Type": "application/json"
        },
        body: JSON.stringify(parameters)
    })
    .then(
        response => {
            if (response.ok)
                console.log("The state file was copied.");
            else
                console.log("Failed to copy the state file.");
        }
    );

Success Response

When a state file has been successfully copied, this controller returns:

Status Code: 204 No Content

Modify a State File

The StateFiles controller allows you to modify state files. Depending on the type parameter, you can either update images obtained from external sources through direct URLs, replace Depositphotos previews with purchased images, specify product tags, or save personalization data.

Note that you can also use the UserImages controller to patch images in user's state files.

Request Payload

This PATCH request expects the type parameter in the request body. You can define one of the following values:

  • MemorySourceReloadAll reloads all images in a state file.
  • PatchImageItems replaces Depositphotos previews with purchased images. This type additionally requires links to the purchased images. For an example, refer to the Depositphotos Assets topic.
  • PatchProductTags defines product tags. This type requires a JSON structure or an array. After you have defined new tags for a product, old tags are discarded.
  • PatchVdpData saves personalization data. This type additionally takes dataSet or itemsData.
  • Composite applies several patches to a state file in a single request.

Example of Reloading Images

After your end users have added images through the Asset Manager, the original files may be changed. If the application requires those changes to be applied to saved state files, you can use this Web API method. This method will trigger Design Editor to download new versions of these images and will replace them in the state file. Reloading images invalidates preview and hi-res links in the cache, thus they are recreated based on the new versions of these images when the application requests them next time.

If the original image has been edited so that its dimensions have changed, then the new image is arbitrarily resized to fit into the old bounds when reloading this image. If any of the original images are deleted, the controller returns the 500 Server error and does not reload images.

const userId = "JohnWood";
const stateId = "1f190673-226d-4c31-87b4-0140805cc445";
const url = `https://localhost:44300/api/users/${userId}/states/${stateId}`;
fetch(url, {
        method: "PATCH",
        headers: {
            "X-CustomersCanvasAPIKey": "UniqueSecurityKey",
            "Content-Type": "application/json"
        },
        body: JSON.stringify({
            type: "MemorySourceReloadAll"
        })
    })
    .then(
        response => {
            if (response.ok)
                console.log("Images were reloaded successfully.");
            else
                console.log("Failed to reload images.");
        }
    );

Example of Specifying Product Tags

You can set product tags as follows:

const userId = "JohnWood";
const stateId = "1f190673-226d-4c31-87b4-0140805cc445";
const url = `https://localhost:44300/api/users/${userId}/states/${stateId}`;
const data = {"product": "postcard", "design": "flowers", "colorTheme": "red"};

fetch(url, {
    method: "PATCH",
    headers: {
        "X-CustomersCanvasAPIKey": "UniqueSecurityKey",
        "Content-Type": "application/json"
    },
    body: JSON.stringify({
        type: "PatchProductTags",
        data: data
    })
});

You may want to save variable data in product tags to implement personalized rendering. In this case, you can organize them in an array so that each element represents a data set to render an output image. The data set, in turn, is an array of objects defining how a single field should appear in the hi-res output. For example, you can define the data to render two product copies with predefined values of the Name, Photo, and Barcode elements as follows:

const data = [
    [
        { name: "Name", value: "Neo", type: "InString" },
        { name: "Photo", value: "https://example.com/Neo.jpg", type: "ImagePlaceholder" },
        { name: "Barcode", value: "1234567", type: "BarcodePlaceholder", barcodeFormat: "EAN-8" }
    ],
    [
        { name: "Name", value: "Trinity", type: "InString" },
        { name: "Photo", value: "https://example.com/Trinity.jpg", type: "ImagePlaceholder" },
        { name: "Barcode", value: "7654321", type: "BarcodePlaceholder", barcodeFormat: "EAN-8" }
    ]
];

Such an object may define the following properties:

  • name=[string] - the element name on the canvas.
  • value=[string] - either text or link to an iamge.
  • type=[string] - the design element type, one of "Image" | "ImagePlaceholder" | "Text" | "InString" | "BarcodePlaceholder".
  • barcodeFormat=[string] - the applicable barcode format, one of "EAN-8" | "EAN-13" | "QR-CODE".
  • barcodeSubType=[string] - the barcode sub type, one of "Phone" | "Url" | "None".

You can also refer to the following example to find out how to save the personalization data through the PatchVdpData request.

Example of Saving Personalization Data

The following example illustrates how you can save itemsData to a state file.

const userId = "JohnWood";
const stateId = "1f190673-226d-4c31-87b4-0140805cc445";
const url = `https://localhost:44300/api/users/${userId}/states/${stateId}`;
const parameters = {
    "type": "PatchVdpData",
    "itemsData": {
        "Name": {
            text: "Christopher",
            font: { fauxItalic: true }
        }
    }
};

fetch(url, {
    method: "PATCH",
    headers: {
        "X-CustomersCanvasAPIKey": "UniqueSecurityKey",
        "Content-Type": "application/json"
    },
    body: JSON.stringify(parameters)
});

Example of a Composite Request

In the request body, you must pass commands - an array with the parameters of the required patches.

The following example illustrates how you can both personalize a state file and specify product tags in a composite request.

const userId = "JohnWood";
const stateId = "c9846515-98ce-4f5a-b0b7-f585be3faf3f";
const url = `https://localhost:44300/api/users/${userId}/states/${stateId}`;
const parameters = {
    "type": "Composite",
    "commands": [
        {
            "type": "PatchVdpData",
            "dataSet": {
                "surfacesData": [
                    {
                        "surfaceBinding": {
                            "surfaceIndexes": [ 0 ]
                        },
                        "data": [
                            {
                                "Name": { "text": "John Wood" }
                            },
                            {
                                "Name": { "text": "Cristopher Bennet" }
                            }
                        ]
                    }
                ]
            },
            "itemsData": null
        },
        {
            "type": "PatchProductTags",
            "data": { "product": "invitation", "design": "BBQ" }
        }
    ]
};

fetch(url, {
    method: "PATCH",
    headers: {
        "X-CustomersCanvasAPIKey": "UniqueSecurityKey",
        "Content-Type": "application/json"
    },
    body: JSON.stringify(parameters)
});

Success Response

When a state file has been successfully patched, this controller returns:

Status Code: 204 No Content

Get Product Tags from a State File

To retrieve product tags, you can make the following request.

Request Example

const userId = "JohnWood";
const stateId = "1f190673-226d-4c31-87b4-0140805cc445";
const url = `https://localhost:44300/api/users/${userId}/states/${stateId}/tags`;

console.log(await (await fetch(url, {
    method: "GET",
    headers: {
        "X-CustomersCanvasAPIKey": "UniqueSecurityKey",
        "Content-Type": "application/json"
    }
}).json));

Success Response

For example, you can get the following response.

Status Code: 200 OK
Content:
{ "product": "postcard", "design": "flowers", "colorTheme": "red" }

Get Variable Items from a State File

To retrieve variable items, you can make the following request.

Request Example

const userId = "JohnWood";
const stateId = "1f190673-226d-4c31-87b4-0140805cc445";
const url = `https://localhost:44300/api/users/${userId}/states/${stateId}/variables`;

(async() => {
    const response = await fetch(url, {
        method: "GET",
        headers: {
            "X-CustomersCanvasAPIKey": "UniqueSecurityKey",
            "Content-Type": "application/json"
        }
    });

    console.log(await response.json());
})()    

Success Response

For example, you can get the following response if a product contains three variable items: a text, an in-string placeholder, and an image.

Status Code: 200 OK
Content:
[
  { "name": "Sale", "value": "BBQ burger", "type": "Text" },
  { "name": "Promo", "value": "2 For $5.99 Each", "type": "InString" },
  { "name": "Photo", "value": null, "type": "Image" }
]

Get the Entire Object Model from a State File

To retrieve a list of design items, you can make the following request.

Request Example

const userId = "JohnWood";
const stateId = "1f190673-226d-4c31-87b4-0140805cc445";
const url = `https://localhost:44300/api/users/${userId}/states/${stateId}/model`;

(async () => {
    const response = await fetch(url, {
        method: "GET",
        headers: {
            "X-CustomersCanvasAPIKey": "UniqueSecurityKey",
            "Content-Type": "application/json"
        }
    });
    const model = await response.json();
    if (response.status === 200) {
        // Output the object model.
        console.log(model);
        // Output the name and type of design items of the first page.
        model.surfaces[0].containers.find(c => c.name === "Main").items.forEach(item => {
            console.log("Name: " + item.name, " Type: " + item.$type);
        });
    }
    else if (response.status === 500)
        // Exception details.
        console.log(result.details);
})()

If the state file contains only two items, this example may return the following list.

Name: design.pdf  Type: ImageItem
Name: caption  Type: PlainTextItem

Success Response

Status Code: 200 OK
Content:
{
    defaultCropMarks: null,
    defaultDesignLocation: {isEmpty: true, x: 0, y: 0},
    defaultSafetyLines: null,
    id: "c1295e78-c3a1-47d0-b80c-d870d1f0e69f",
    name: null,
    surfaces: [
        {width: 161.517532, height: 161.517532, rotateAngle: 0, tags: {...}, size: "161.517532, 161.517532", ...}
    ],
    tags: {printColorSpace: "Rgb", userId: "default"},
    version: "5.32.100",
    watermarkConfig: {text: {...}, image: null, visibility: {...}}
}

Configuring Webhooks

As an alternative to the default location, Design Editor allows you to organize external storage for state files and implement custom HTTP callbacks triggered by saving, loading, and deleting the state files in the Design Editor. To enable such webhooks, you need to define optional keys ExternalStatePushUrl, ExternalStatePullUrl, and ExternalStateDeleteUrl in AppSettings.config.

<appSettings>
    <add key="ExternalStatePushUrl" value="https://example.com/api/state/push/{userId}/{stateId}" />
    <add key="ExternalStatePullUrl" value="https://example.com/api/state/pull/{userId}/{stateId}" />
    <add key="ExternalStateDeleteUrl" value="https://example.com/api/state/delete/{userId}/{stateId}" />
    <add key="ExternalStateSecurityKey" value="UniqueSecurityKey" />
    <add key="UserDataFolder" value="..\userdata" />
</appSettings>

When you define these endpoints, the Design Editor sends a state file to ExternalStatePushUrl and does not save it to the local user data folder if it receives a success response. When loading a state file, the editor searches for this file in its local storage and cache first. Then, the editor tries to pull this file from ExternalStatePullUrl. If the state file is not found, an exception occurs.

To pass the state ID and user ID, use the {stateId} and {userId} values, correspondingly. You can specify them as either resource paths or query parameters in your endpoints, for example, https://example.com/api/state/push?userId={userId}&stateId={stateId}.

Important

Your service implementing webhooks must provide these Push and Pull endpoints. Push is the POST method, and Pull implements GET and HEAD methods. Using both GET and HEAD methods ensures optimal operation and traffic savings. The Pull endpoint must pass the Etag and LastModified headers when responding.

When Design Editor makes these calls, it passes the X-ExternalStateStorageApiKey header with the specified security key.

A Sample Implementation

This sample illustrates how you can implement requests to pull and push state files.

[RoutePrefix("api/state")]
public class WebHookController : ApiController
{
    [HttpPost]
    [Route("push/{userId}/{stateId}")]
    public HttpResponseMessage Push(string userId, string stateId)
    {
        // Retrieve a file from the request.
        var file = HttpContext.Current.Request.Files[0];

        if (file == null)
            return new HttpResponseMessage(HttpStatusCode.BadRequest);
       
        // Create a file name based on userId and stateId.
        var fileName = HostingEnvironment.MapPath("~/states") + $"/{userId}_{stateId}.st";

        file.SaveAs(fileName);

        return new HttpResponseMessage(HttpStatusCode.OK);
    }
   
    [HttpGet]
    [HttpHead]
    [Route("pull/{userId}/{stateId}")]
    public HttpResponseMessage Pull(string userId, string stateId)
    {
        // Obtain a file name based on userId and stateId.
        var fileName = HostingEnvironment.MapPath("~/states") + $"/{userId}_{stateId}.st";

        if (!File.Exists(fileName))
        {
            return new HttpResponseMessage(HttpStatusCode.NotFound);
        }

        var fileInfo = new FileInfo(fileName);
        var etag = CalculateEtag(fileInfo);
        var lastModified = fileInfo.LastWriteTimeUtc;
       
        var fileStream = Request.Method != HttpMethod.Head ? File.OpenRead(fileName) : null;
        return CreateResponse(fileStream, "application/octet-stream", fileInfo.Length, etag, lastModified, "application/zip");
    }

    private string CalculateEtag(FileInfo fileInfo)
    {
        using (var fileStream = File.OpenRead(fileInfo.FullName))
        using (var md5 = MD5.Create())
        {
            var hash = md5.ComputeHash(fileStream);
            return System.Convert.ToBase64String(hash);
        }
    }

    private static HttpResponseMessage CreateResponse(Stream stream, string mimeType, long fileLength, string etag, DateTime lastModified, string attachmentFileName = null)
    {
        var content = stream != null
            ? (HttpContent)new StreamContent(stream)
            : new EmptyContent();
        var response = new HttpResponseMessage(HttpStatusCode.OK)
        {
            // Send the state file in the request body.
            Content = content
        };
        response.Content.Headers.ContentType = new MediaTypeHeaderValue(mimeType);
        response.Content.Headers.LastModified = lastModified;
        response.Content.Headers.ContentLength = fileLength;
       
        response.Headers.ETag = new EntityTagHeaderValue($"\"{etag}\"");
        response.Headers.CacheControl = new CacheControlHeaderValue
        {
            Public = true,
            MaxAge = TimeSpan.FromHours(12)
        };

        // Assign a file name to the content if needed.
        if (attachmentFileName != null)
        {
            response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
            {
                FileName = attachmentFileName
            };
        }

        return response;
    }

}

public class EmptyContent : HttpContent
{
    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
    {
        return Task.CompletedTask;
    }
    protected override bool TryComputeLength(out long length)
    {
        length = 0L;
        return true;
    }
}

Patching Images

Design Editor allows you to download and upload user images through the Web API. After your users have created their products, you may want to improve their images before the PDF generation. In this case, you can extract user images from user states with this API, change these images on a local computer, and then put them back using the same API. Moreover, you don't have to manually download these images or photos in a browser for a single product. You can implement a desktop application to download user images from orders that were placed within a certain period of time, say, daily or all recent orders. Your application could automatically put these images into a folder where you can process them. When you finish working with images, this application could upload the changed copies back to your site with the same API.

This API works based on HTTPS requests and is handled by The UserImages controller (~/api/UserImages) allows you to implement this workflow.

Function Request type URL Description
Create and download an image archive POST ~/api/UserImages/create Creates an archive of user images which they use in a product. It requires a pair of UserId and StateId.
Upload an image archive POST ~/api/UserImages/upload Uploads an archive and pastes images into corresponding state files. It uses file names of the images to define the destination.

To make changes in downloaded images and apply them to your product, you should unpack the archive, edit the images, and then pack them back. Make sure that image names and their hierarchy remain unchanged when you pack the images back into an archive.

Image file names have the following format: <UserId>_<StateId>_<ImageId>.<ext>

Sample

The following example displays a form that allows you to archive images for a specified pair of UserId and StateId.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>User Images API Sample</title>
    <script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.js">
    </script>
    <script language="javascript">
        // Set a link to the UserImages controller.
        var url = "https://example.com/cc/api/UserImages";
        // Set a unique key for using the Web API.
        var apiKey = "UniqueSecurityKey";

        // Define a function for obtaining an image archive.
        var getArchive = function() {
            var pairs = [];
            // Set a product state ID and a user ID for whoever created the state.
            pairs.push({UserId: "default", StateId: "a37a86bd-2d75-4f6e-a0e2-01fc4e4fc144"});

            // Make the create request.
            $.ajax({
                url: url + "/create",
                type: "POST",
                headers: { "X-CustomersCanvasAPIKey": apiKey },
                dataType: "json",
                contentType: "application/json; charset=utf-8",
                data: JSON.stringify(pairs)
            }).
            fail(function (d) { console.log(d.statusText); }).
            done(function (d) {
                console.log(d);
                window.location = d;
            });
        }

        // Define a function for uploading the updated archive back to a server.
        var uploadArchive = function () {
            var data = new FormData(document.getElementById("upload_archive"));

            // Make the upload request.
            $.ajax({
                url: url + "/upload",
                type: "POST",
                headers: { "X-CustomersCanvasAPIKey": apiKey },
                data: data,
                processData: false,
                contentType: false
            });
        }
    </script>
</head>
<body>
    <h3>Download Images</h3>
    <input type="button" value="Get archive" onclick="getArchive()" />

    <h3>Upload Images</h3>
    <form id="upload_archive" enctype="multipart/form-data">
        File: <input type="file" name="file" />
        <input type="button" value="Upload archive" onclick="uploadArchive()" />
    </form>

</body>
</html>
Was this page helpful?
Thanks for your feedback!
Back to top Copyright © 2001–2024 Aurigma, Inc. All rights reserved.
Loading...
    Thank for your vote
    Your opinion is important to us. To provide details, send feedback.
    Send feedback