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 projects and account, so 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 version of the API is denoted in the url path, for example: https://api.qwilr.com/alfred/foundry/v0/

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

The next version is version 1 and the documentation for it can be found here.

Domain

As mentioned in Versioning, the url to send your requests is: https://api.qwilr.com/alfred/foundry/v0/

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. The Foundry API allows you to create, delete and replace your projects by sending through JSON objects.

The Project JSON object

Attribute name Attribute type Description
name String The name of the project
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. Currently only supports password protection.
tags Array[String] An array of tags to apply to the project
published Boolean If true, any quote block in the project that has Accept enabled will be acceptable. Otherwise, if false, the project can’t be accepted.

The ProjectDetails JSON object

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

Endpoints

Create Project
POST /projects

Usage: Creates a new qwilr project

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

Delete project
DELETE /projects/$projectId

Usage: Deletes a qwilr project

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 project, however you can replace an existing project 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 project
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/v0/projects \
  -H 'authorization: Bearer YOUR_KEY' \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
    "data" : {
        "name": "API Sample",
        "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/v0/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": "Sample Section",
                                    "lineItems": [
                                        {
                                            "description": "These samples are for testing purposes only",
                                            "itemType": {
                                                "text": {
                                                    "optional": {
                                                        "enabled": false
                                                    }
                                                }
                                            }
                                        },
                                        {
                                            "description": "Sample Sampling Sample",
                                            "itemType": {
                                                "fixedCost": {
                                                    "cost": 19.11,
                                                    "details": {
                                                        "unitName": "Sample Sampling",
                                                        "quantity": 1,
                                                        "taxExempt": false,
                                                        "discount": 0.0
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            ],
                            "currency": "AUD",
                            "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, or QuoteBlock.
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 in the Qwilr app). 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 (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:
  • “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.
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
htmlContent 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 ONE of the two Double type fields:
  • percent
  • fixed
currency CurrencyCode ISO 4217 code for the currency being used in the Quote block
accept AcceptOptions (optional) Any accept settings for the Quote block. See AcceptOptions full a definition.
taxIds Array[String] An array of the ids of taxes in your Qwilr account that you would like to apply to this Quote block
display Object An object containing a series of Boolean flags to show/hide various aspects of the Quote block:
  • quoteTotal: Show the quote total
  • quoteSubTotal: Show the pre-tax and pre-discount quote total
  • taxes: Show the total tax amount
  • totalInclTax: Show the total including tax
  • lineItemUnits: Show the unit for each line item
  • lineItemUnitPrice: Show the price per unit for each line item
  • sectionTotalsOnly: Hide individual line items and show just the total for each section
  • sectionSubTotals: Show the sub total for each section
  • sectionDiscounts: Show the discounts being applied to each section
customLabels Object (optional) Replacement Strings for various parts of the Quote. Any of the following can be included in the object to replace the default used by Qwilr:
  • total
  • subtotal
  • excludingTax
  • discount
  • per
Text Items:
{
  description: String
  itemType:
    text:
      optional:
        enabled: Boolean
}


Rate Items:
{
  description: String
  itemType:
     rate:
      rateId: String
       details:
        unitName: String
        quantity: Integer
        interactive: InteractiveOptions (optional)
        taxExempt: Boolean
        discount: Double
}

Fixed Cost Items:
{
 description: String
 itemType:
   fixedCost:
     cost: Double
     details:
       unitName: String
       quantity: Integer
       interactive: InteractiveOptions (optional)
       taxExempt: Boolean
       discount: 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 AcceptOptions JSON object

Attribute Name Attribute Type Description
customAcceptButton Object (optional) Customize the accept button label and accept completion text with the fields:
  • buttonText
  • completionText
eSign Boolean Specify whether a signature is required when a project is accepted.
customFormId String (optional) A unique identifier for a custom form to add to the acceptance flow in this quote block
payment Object If you want your acceptor to pay through Qwilr when accepting, add the following object for payment:
{
 payNow: true,
 businessName: String (how you wish your business name to appear on the accept form),
 paymentInfo: String (any additional information you would like to include on the payment form),
 payPercentage: Double (the amount of the Quote total that the acceptor will pay)
}
Otherwise:
{
 payNow: false
}

Copying a Saved Block

To copy an existing saved block, we first need to grab the saved block’s ID from the UI. To do, go to Saved Block library and for the saved block you wish to use, click the "More" 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.

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

As the content of your saved blocks, should be customised 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:

Webhooks

Adding Webhooks

POST /alfred/v0/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/v0/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 \
  http://api.qwilr.com/alfred/foundry/v0/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
  }
}'

Replace Existing Project

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

curl -X POST \
  http://api.qwilr.com/alfred/foundry/v0/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
  }
}'

Quote Block With Accept

An example of a quote block with accept enabled can be found to the right.


curl -X POST \
  http://api.qwilr.com/alfred/foundry/v0/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": "Sample Section",
                                    "lineItems": [
                                        {
                                            "description": "These samples are for sample purposes only",
                                            "itemType": {
                                                "text": {
                                                    "optional": {
                                                        "enabled": false
                                                    }
                                                }
                                            }
                                        },
                                        {
                                            "description": "Sample Sampling Sample",
                                            "itemType": {
                                                "fixedCost": {
                                                    "cost": 19.11,
                                                    "details": {
                                                        "unitName": "Sample Sampling",
                                                        "quantity": 1,
                                                        "taxExempt": false,
                                                        "discount": 0.0
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            ],
                            "currency": "AUD",
                            "taxIds": [],
                            "display": {
                                "quoteTotal": true,
                                "quoteSubTotal": false,
                                "taxes": false,
                                "totalInclTax": false,
                                "lineItemUnits": false,
                                "lineItemUnitPrice": false,
                                "sectionTotalsOnly": false,
                                "sectionSubTotals": false,
                                "sectionDiscounts": false
                            },
                            "accept": {
                                "customAcceptButton": {
                                    "buttonText": "Commit thyself",
                                    "completionText": "Thank you for your offering"
                                },
                                "eSign": true,
                                "payment": {
                                    "payNow": true,
                                    "businessName": "Sample Corp",
                                    "paymentInfo": "c/o Sample Conglomerate",
                                    "payPercentage": 100.00
                                }
                            }
                        }
                    }
                }
            }
        ],
        "tags": [],
        "published": true
    }
}'

Delete a Project

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


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