NAV Navbar
curl

Introduction

Welcome to the Qwilr Foundry API documentation. With our API you'll be able to generate Qwilr Pages programmatically. This means you can generate custom quotes, create pages when someone fills out a form, or anything else. The sky is the limit.

Our API is organized around REST. All calls made are live. If you need to test outside of your live account, get in touch with our team for options around that.

If you're looking for help with the Qwilr app you can find that in our help documentation.

If you have any questions about our API, please get in touch at help@qwilr.com.

Authentication

All requests to Foundry need to be authenticated with your account's API key. You can find your API key in the Qwilr API Settings:

API Key

Your API key allows anyone to access your Qwilr Pages and account. Be sure to keep it secret! Do not share your secret API keys in any public spaces such as your source repository, client-side code, and so forth.

When making a request:

Versioning

The Foundry API is currently in version 1, an early but stable beta. The version of the API is denoted in the url path, for example: https://api.qwilr.com/alfred/foundry/v1/

Backwards-incompatible changes will result in a new version of the API being released, with clearly defined lifetime support lengths. The current version 1 will continue to be supported for a reasonable period of time once the next version is released.

The previous version was version 0 and the documentation for it can be found here.

Domain

Base URL
https://api.qwilr.com/alfred/foundry/v1/

The url to send your requests is: https://api.qwilr.com/alfred/foundry/v1/

All paths mentioned below should be prefixed with this.

Data Format Notes

  1. The JSON sent to the API should be wrapped in a top-level object with one attribute “data” that the rest of the data sits under.
  2. Any optional attributes do not need to be included, but when they are the entirety of the optional structure needs to be included (unless any of those attributes are marked “optional”)

Projects

Project objects correspond to projects in the Qwilr UI, allowing for the creation of a public-facing Qwilr Page. The Foundry API allows you to create, delete and replace your Pages by sending through JSON objects.

The Project JSON object

Attribute name Attribute type Description
name String The name of the Page
globalSubstitutions Substitutions Any variable substitutions to use across the project content
blocks Array[Block] An array of block definitions, each either a new block or copying an existing saved block (the Block object is defined below)
securitySettings SecuritySettings (optional) Any security settings to activate for the project. We currently only supports password protection.
tags Array[String] An array of tags to apply to the project, great for organization and categorization
published Boolean If true, your Qwilr Page will be live. Any Quote block in the project that has Accept enabled will be acceptable. Otherwise, if false, the project will be in a draft state and not publicly viewable or acceptable.

The ProjectDetails JSON object

Attribute name Attribute type Description
projectId String A unique identifier for the Page
project Project The project Page, defined above.
shareUrl String A URL that can be used to share the Page.

Endpoints

Create Project
POST /projects

Usage: Creates a new Qwilr Page

Requires: A Project object in the body
Returns: ProjectDetails object

Delete project
DELETE /projects/$projectId

Usage: Deletes a Qwilr Page

Requires: $projectId - The ID of the project
Returns: 200 status on successful deletion

Replace project
POST /projects/$projectId/replace

Usage: The Foundry API does not allow for the direct updating of a Page, however you can replace an existing Page with the structure provided in the request to this endpoint.
*Please note - This will remove the project you are replacing.

Requires: $projectId: The ID of the Page
Provide a Project object in the body
Returns: ProjectDetails object

Blocks

The Block object can be either the NewBlock object or the CopyBlock object.

The CopyBlock JSON object

curl -X POST \
  http://api.qwilr.com/alfred/foundry/v1/projects \
  -H 'authorization: Bearer YOUR_KEY' \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
    "data" : {
        "name": "Bat Cave Building Specs",
        "globalSubstitutions": {},
        "blocks": [
            {
                "copy": {
                    "blockId": "d6nAb21QChakaw1JkD3ty4D-gLBMHQ",
                    "substitutions": {}
                }
            }
        ],
        "tags": [],
        "published": false
    }
}

The CopyBlock object will take an existing saved block in your library and create a copy, substituting any variables that are defined in the content. The structure below is wrapped in an object with one field “copy”. For example:

“blocks”: [
   {
     “copy”: ..(CopyBlock object)..
   }
]

Attribute Name Attribute Type Description
blockId String The unique identifier for the saved block. To get this, see “Copying a Saved Block” below.
substitutions Substitutions Any content variable substitutions to apply to the copied block
foldable Object (optional) A foldable settings Object, which contains the following attributes:
  • isFoldable a Boolean to determine whether the block can be folded
  • foldLabel a String to apply as a label to the folding button
  • startFolded a Boolean to start the block in the folded state, or unfolded.

The NewBlock JSON object

curl -X POST \
  http://api.qwilr.com/alfred/foundry/v1/projects \
  -H 'authorization: Bearer YOUR_KEY' \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
    "data" : {
        "name": "API Sample",
        "globalSubstitutions": {},
        "blocks": [
            {
                "new": {
                    "blockType": {
                        "quoteBlock": {
                            "htmlContent": "",
                            "sections": [
                                {
                                    "name": "Climbing Gear",
                                    "lineItems": [
                                        {
                                            "description": "Solid adamentium grapling hook. Great for scaling buildings.",
                                            "itemType": {
                                                "text": {
                                                    "optional": {
                                                        "enabled": false
                                                    }
                                                }
                                            }
                                        },
                                        {
                                            "description": "Sample Sampling Sample",
                                            "itemType": {
                                                "fixedCost": {
                                                    "cost": 99.99,
                                                    "details": {
                                                        "unitName": "Hooks",
                                                        "quantity": 1,
                                                        "taxExempt": false,
                                                        "discount": 0.0
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            ],
                            "currency": "USD",
                            "taxIds": [],
                            "display": {
                                "quoteTotal": false,
                                "quoteSubTotal": false,
                                "taxes": false,
                                "totalInclTax": false,
                                "lineItemUnits": false,
                                "lineItemUnitPrice": false,
                                "sectionTotalsOnly": false,
                                "sectionSubTotals": false,
                                "sectionDiscounts": false
                            }
                        }
                    }
                }
            }
        ],
        "tags": [],
        "published": false
    }
}

To create a brand new Block, use the NewBlock object. Similar to the CopyBlock object, the below structure is wrapped in a “new” attribute:

“blocks”: [    {      “new”: ..(NewBlock object)..    } ]

As a best practice, if you are reusing a block multiple times across projects these should be saved in your saved block library with variables in the content for areas that need customization. This will help lower the payload you need to send through.

Attribute Name Attribute Type Description
blockType Object The block contents, this can be one of TextBlock, SplashBlock, SourceBlock, VideoBlock, QuoteBlock, or AcceptBlock.
styleName String (optional) The name of the style you wish to apply to the block.
foldable FoldableSettings (optional) A foldable settings Object, which contains the following attributes:
  • isFoldable a Boolean to determine whether the block can be folded
  • foldLabel a String to apply as a label to the folding button
  • startFolded a Boolean to start the block in the folded state, or unfolded.

Block Types

When creating a new block, you need to specify the appropriate type of block (which correspond to the blocks available within Qwilr). For each of these, wrap their contents with an object with one attribute that is the object’s name in camelCase. For example, the textBlock object would look like:

{    “textBlock”: {      “htmlContent”: “...”  } }

The TextBlock JSON object

Attribute Name Attribute Type Description
htmlContent String HTML content for the text block

The SplashBlock JSON object

Attribute Name Attribute Type Description
resourceUrl String URL for image/video background
splashSize String Can be one of the following (representing how much of the page the splash block will take up):
  • “third”
  • “half”
  • “full”
tint String (optional) RGB value for the tint color, prefixed with a “#” (e.g. “#222”).
content Object (optional) Object representing the splash block’s content with two fields:
  • contentBackground a boolean for whether the content should have a background to differentiate it from the splash background
  • htmlContent a string of HTML to use for the content of the splash block

The SourceBlock JSON object

Used for creating a Embed block in the project.

Attribute Name Attribute Type Description
sourceType String The source to use for the Embed block, this can be one of the following:
  • “googleMaps”
  • “googleForm”
  • “googleSheet”
  • “typeForm”
  • “slideShare”
  • “infogram”
  • “iframe”
url String The URL to pass into the Embed block for the particular source.

The VideoBlock JSON object

Attribute Name Attribute Type Description
headerContent String The HTML content to be placed in the header of the Video block.
url String The url to pass into the Video block to use as a source. The video block supports content from:
  • YouTube
  • Wistia
  • Vimeo
  • Brightcove
videoSize String The sizing style of the Video block, can be one of:
  • “small”
  • “medium”
  • “large”

The QuoteBlock JSON object

The Quote block is more complicated than other blocks, due to the additional configuration options and detail of data. The following section breaks down the object provided on creation:

Attribute Name Attribute Type Description
htmlQuoteHeader String The descriptive HTML content to be placed in the header of the Quote block.
sections Array[Object] An array of objects representing sections in the Quote block. Composed of two fields:
  • name: A string for the quote header
  • lineItems: An Array[LineItem] with each element being a line item in the section. See below for the definition of LineItem.
discount Object (optional) An object describing a quote block-wide discount. This object can have only one of the two Double field types:
  • percent
  • fixed
selectionType String Designates whether how the user selects the quote in the context of the overall page

One of combined, single or multi
cssBlockName String Defaults to quote-v2-module
enabledTaxes Array[String] An array of the ids of taxes in your Qwilr account that you would like to apply to this Quote block
settings Object Object contains multiple settings, they are:
  • labelSetId: specifies a custom label set used for replacing certain words
  • style: style for the block
  • excludeNavigation: whether to exclude the navigation widgets in the quote block
  • viewOptions: see settings.viewOptions
  • enabledTaxes: Array of the ids of taxes in your Qwilr account that you would like to apply to this Quote block
settings.viewOptions Object (optional) View options for block:
  • showTaxTotals: whether to display tax totals in Quote block boolean
  • showExTax: Display total exclusive of tax boolean
  • showQuoteTotals: Display total of quote
  • showDecimalPlaces: Display values with decimals
Text Items:
{
  description: String
  itemType:
    text:
      optional:
        enabled: Boolean
        selected: Boolean
}


Rate Items:
{
  description: String
  itemType:
    variable:
      variableId: String
      details:
        quantity: Integer
        interactive: InteractiveOptions (optional)
        taxExempt: Boolean
        discount: DiscountType 

}

Fixed Cost Items:
{
   description: String
  itemType:
    fixedCost:
      cost: Double
      details:
        unitName: String
        quantity: Integer
        interactive: InteractiveOptions (optional)
        taxExempt: Boolean
        discount: DiscountType

}

InteractiveOptions type
{
   optional: 
      enabled: Boolean
      selected: Boolean
      quantity: Boolean
}

DiscountType
{
  percent: Double
}
Or
{ 
  Fixed: Double
}

The LineItem JSON object

There are 3 types of line items that can be in a Qwilr Quote, which are included within a section’s lineItems array.

Text Items, for displaying information without an associated price.

Rate Items use a pre-existing rate to determine the pricing per unit.

Fixed Cost Items, which need the cost per unit to be specified.



















The AcceptBlock JSON object

Attribute Name Attribute Type Description
htmlContent String The description of the Accept block
name Boolean Simple name of the Accept block
settings Object Settings for the Accept block
  • paymentOptions
  • Accepters
settings.paymentOptions Object Payment options are:
  • payNow: Can user pay now
  • optionalPayment: is payment optional
  • partPayment: Can accepter pay partially
settings.accepters Object Describes accepters for project
  • Number: number of accepters
  • enablePrefilledNames: can the names be prefilled on acceptance
  • prefilledNames: Array of names

Copying a Saved Block

To copy an existing saved block, grab the saved block's ID from withing your Qwilr account. To do this, go to Saved Block library and for the saved block you wish to use, enable the show block id option:

Saved Block

Then grab the block ID:

Block ID

Use this ID in the blockId field sent to Qwilr, along with any foldable options and variable substitutions.

Creating a new Block

Creating a new block takes a larger payload as there are several options to be passed through, particularly for the Quote block. Check out our Examples section for a variety of different ways to create blocks through the Foundry API.

Get Page Information API Endpoints

With the Foundry API you'll also be able to retrieve information about existing pages.

Get Page Statuses

GET https://api.qwilr.com/alfred/foundry/v1/status

Returns status for Pages

Parameter Parameter Type Description
start Integer This denotes the starting point on the a set of results. (For example starting at result 26)
limit Integer The total number of results to return (maximum is 100, default 25)

Results array

[
{
   projectId: "5b4d906b0aab5930c95dc29e",
   status: "live",
   viewCount: 1
},
{...}
]

Get Accepted Pages

GET https://api.qwilr.com/alfred/foundry/v1/accepted

Fetches accepted Pages

Parameter Parameter Type Description
start Integer This denotes the starting point on the a set of results. (For example starting at result 26)
limit Integer The total number of results to return (maximum is 100, default 25)
before String<ISODate>
See here for more info
Limit results to those accepted before this date-time. Times are in UTC
(eg. “2018-07-17T06:12:10Z”)
after String<ISODate> Limit limit results to those accepted after this date-time. Times are in UTC

Results array

[

   {
     id: "5b4d906b0aab5930c95dc29e",
     acceptanceData: { … }
]

Content

In the object definitions above there were two specific String types: HtmlContent and TextContent. These are to distinguish different restrictions applied to strings passed into the API. TextContent is treated as raw text, with any HTML data escaped so that what is passed in will be displayed verbatim.

HtmlContent will allow the passing of a subset of HTML tags and attributes, allowing you to pass in rich text for that field.

The following tags are whitelisted for HtmlContent, with any allowed tags mentioned. Any other tags or attributes will be filtered out of the content:

Substitutions

The content of your saved blocks should be customized for the particular use case they’re being used for, variables can be added in that will be replaced with substitutions upon project creation.

To denote a variable in the content use double curly braces around the variable name:

{{variableName}}

Then, within a relevant substitutions object, specify the mapping between “variableName” and the corresponding value.

Your substitutions can be added in any of 3 levels of “scope”, which define how widespread the substitution will be applied. These 3 levels are:

One note regarding substitutions and scope: if you have the same variable name defined for multiple scopes, the “smallest” scope will be used. Allowing account-level substitutions to be defined as defaults, but for a particular project these can be overridden.

A special case for substitutions are “looping” variables, Array values where each element should be applied separately. For example, if each element should be a new paragraph. These looping values are wrapped with:

{{#loopingVariable}}
{{/loopingVariable}}

Each element in the array is an object, with the attributes on the element being used within those looping values. For example:

{{#loopingVariable}}
We are big fans of: {{technology}} because it is {{reason}}.
{{/loopingVariable}}

Please note: HTML will be escaped in substitutions, so any HTML tags added to a variable will be displayed verbatim.

Webhooks

Adding Webhooks

POST /alfred/v1/notifications
Payload:
{
     event: String
     target_url: String
}

The event is the type of notification event you want to be notified about, the currently available events are:
projectCreated
projectPublished
projectFirstViewed
projectAccepted

The target_url is the endpoint you would like the notification data to be POST-ed to.

The data returned from a successful add notification request is to the right.


Add Notification:
{
     event: String
     target_url: String
     id: String
}

The event and target_url are the same as described above, the id field is to identify the new webhook should you want to remove it later.

Removing Webhooks

DELETE /alfred/v1/notifications
Payload:
{
      id: String
}

The id is the id field returned when you added a webhook and is unique to each webhook.

Using Webhooks

For all notifications, the data sent by Qwilr to your chosen webhook endpoint is structured is to the right.

{
     firstName: String
     lastName: String
     email: String
     link: String
     accountName: String
     projectName: String
     type: String
}

Where:

Errors

Qwilr uses conventional HTTP response codes to indicate the success or failure of an API request. Codes in the 2xx range indicate success, codes in the 4xx range indicate an error that failed given the information provided (e.g., a required parameter was omitted, a charge failed, etc.), and codes in the 5xx range indicate an error with Qwilr's servers.

Some example error codes:

Error Code Meaning
400 Bad Request — Check the “message” field that is returned with this error
401 Unauthorized — Please check that your Authorization header is present and that the value is “Bearer yourSecretApiKey”
500 Internal Server Error — Something erroneous has occurred on our end! Please send details of the API request to help@qwilr.com and we will work to unblock you and fix the issue.
503 Service Unavailable — We're temporarily offline for maintenance. Please try again later.

Examples

Create New Project

An example of creating a new project can be found to the right.

curl -X POST \
  https://api.qwilr.com/alfred/foundry/v1/projects \
  -H 'authorization: Bearer YOUR_KEY' \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
  "data": {
    "name": "Acme Corp Proposal",
    "globalSubstitutions": {},
    "blocks": [
      {
        "new": {
          "blockType": {
            "textBlock": {
              "htmlContent": "<h1>Acme Corp - Digital Marketing Proposal</h1>"
            }
          },
          "foldable": {
            "isFoldable": true,
            "foldLabel": "Open me!",
            "startFolded": true
          }
        }
      },
      {
        "new": {
          "blockType": {
            "splashBlock": {
              "resourceUrl": "http://68.media.tumblr.com/f264b862a6bf8ba5b9f06bf8bf4ea635/tumblr_na0kcnVUoi1st5lhmo1_1280.jpg",
              "splashSize": "full",
              "content": {
                "contentBackground": true,
                "htmlContent": "<h1>Welcome to the future of digital marketing</h1>"
              }
            }
        },
          "foldable": {
            "isFoldable": true,
            "foldLabel": "Open me!",
            "startFolded": true
          }
        }
      },
      {
        "new": {
          "blockType": {
            "sourceBlock": {
              "sourceType": "googleMaps",
              "url": "https://www.google.com.au/maps/place/7+Hudson+St,+Redfern+NSW+2016/@-33.8896174,151.1972541,17z/data=!3m1!4b1!4m5!3m4!1s0x6b12b1d9d24aa3b1:0x6976dd7bcc793e6f!8m2!3d-33.8896174!4d151.1994428?hl=en"
            }
          }
        }    
      }
    ],
    "tags": [
      "sales",
      "marketing-campaign-june"
    ],
    "published": true
  }
}

Create new Project with Quote and Accept BLock

An example of project created with both a quote and an accept block can be found to the right


curl -X POST \
  https://api.qwilr.com/alfred/foundry/v1/projects \
  -H 'authorization: Bearer YOUR_KEY' \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
  "data": {
    "name": "Test project with quote and accept blocks",
    "globalSubstitutions": {},
    "blocks": [{
      "new": {
        "blockType": {
          "quoteBlock": {
            "htmlQuoteHeader": "<h2>Hello</h2><p>World</p>",
            "sections": [{
              "htmlDescription": "<h2>Hello</h2><p>World</p>",
              "discount": {
                "fixed": 100
              },

              "viewSettings": {
                "itemsViewable": true,
                "itemsCollapsed": true,
                "showRateAndQuantity": true,
                "showCost": true,
                "showSubtotal": true
              },

              "lineItems": [{
                  "htmlDescription": "<h1>Variable Item</h1>",
                  "itemType": {
                    "variable": {
                      "variableId": "WclqdeTadlc",
                      "details": {
                        "quantity": 3,
                        "taxExempt": true,
                        "discount": {
                          "percent": 10
                        }
                      }
                    }
                  }
                },
                {
                  "htmlDescription": "<p>fixed cost Item</p>",
                  "itemType": {
                    "fixedCost": {
                      "cost": 1000,
                      "details": {
                        "unitName": "Unit",
                        "quantity": 10,
                        "taxExempt": false,
                        "interactive": {
                          "isOptional": true,
                          "isOptionalSelected": true,
                          "isQuantityOptional": false,
                          "minQuantity": 0,
                          "maxQuantity": 0

                        },
                        "discount": {
                          "percent": 10
                        }
                      }
                    }
                  }
                }
              ]
            }],
            "selectionType": "combined",
            "cssBlockName": "quote-v2-module",
            "discount": {
              "percent": 5
            },
            "settings": {
              "labelSetId": "uniqueId1234",
              "style": "test-style",
              "excludeNavigation": true,
              "viewOptions": {
                "showTaxTotals": true,
                "showExTax": true
              },
              "enabledTaxes": [
                "1234"
              ]
            }
          }
        }
      }
    }, {
      "new": {
        "blockType": {
          "acceptBlock": {
            "htmlContent": "<h1>Hello</h1><p>World</p>",
            "name": "My Accept Block",
            "settings": {
              "paymentOptions": {
                "payNow": true,
                   "optionalPayment": false,
                "partPayment": true
              },
              "esignEnabled": false,
              "style": "qwilr-standard",
              "accepters": {
                "number": 2,
                "enablePrefilledNames": true,
                "prefilledNames": [
                  "John Rogers",
                  "Arthur Smith"
                ]
              }
            }
          }
        }
      }
    }],
    "tags": [],
    "currency": "AUD",
    "published": true
  }
}'


Replace Existing Project

An example of replacing a project can be found to the right.

curl -X POST \
  http://api.qwilr.com/alfred/foundry/v1/projects/$projectId/replace \
  -H 'authorization: Bearer YOUR_KEY' \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
  "data": {
    "name": "Acme Corp Proposal",
    "globalSubstitutions": {},
    "blocks": [
      {
        "new": {
          "blockType": {
            "textBlock": {
              "htmlContent": "<h1>Acme Corp - Digital Marketing Proposal</h1>"
            }
          },
          "foldable": {
            "isFoldable": true,
            "foldLabel": "Open me!",
            "startFolded": true
          }
        }
      },
      {
        "new": {
          "blockType": {
            "splashBlock": {
              "resourceUrl": "http://68.media.tumblr.com/f264b862a6bf8ba5b9f06bf8bf4ea635/tumblr_na0kcnVUoi1st5lhmo1_1280.jpg",
              "splashSize": "full",
              "content": {
                "contentBackground": true,
                "htmlContent": "<h1>Welcome to the future of digital marketing</h1>"
              }
            }
          },
          "foldable": {
            "isFoldable": true,
            "foldLabel": "Open me!",
            "startFolded": true
          }
        }
      }
    ],
    "tags": [
      "sales",
      "marketing-campaign-june",
      "replaced"
    ],
    "published": false
  }
}'

Delete a Project

An example of deleting a project can be found to the right.


curl -X DELETE \
  http://api.qwilr.com/alfred/foundry/v1/projects/$projectId \
  -H 'authorization: Bearer YOUR_KEY' \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json'
```