NAV Navbar
curl
  • Introduction
  • Authentication
  • Versioning
  • Domain
  • Data Format Notes
  • Projects
  • Blocks
  • Content
  • Substitutions
  • Webhooks
  • Errors
  • Examples
  • Introduction

    Welcome to the Qwilr REST API documentation. If you’re looking for help with the Qwilr app you can find that in our help docs.

    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 Foundry API is currently in version 0, an early-access but stable beta. 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. The current version 0 will continue to be supported for a reasonable period of time once the next version is released.

    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://qwilr.dev/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://qwilr.dev/alfred/foundry/v0/projects/5938a8779885e5a509b7a676/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://qwilr.dev/alfred/foundry/v0/projects/Project_Here \
      -H 'authorization: Bearer YOUR_KEY' \
      -H 'cache-control: no-cache' \
      -H 'content-type: application/json'
    ```