API Navigator

Paperlex API — Version 1

Endpoints

All requests to the Paperlex API occur over HTTPS.

Required Parameters

Each request to the Paperlex API must include:

Example:

curl https://sandbox.api.paperlex.com/v1/contracts.json?token=b53b0c15dce176b4

Error handling

If you pass an unknown UUID or try to retrieve a version of a contract or template that doesn't exist, an HTTP code of 404 will be returned.

All other errors are returned with an HTTP code of 422 and a JSON hash containing an "error" key that describes the problem.

Example Error: {"error":"Couldn't find your API key"}

Tutorial

Cut to the chase and start using the API by following the tutorial.

You can also follow along in Ruby by installing the official Paperlex gem:

gem install paperlex

… and visiting https://github.com/paperlex/paperlex-api-client-ruby for sample code.

PaperlexML

The Paperlex markup language (PaperlexML) is based on Liquid, with extra tags designed for legal documents.

Auto-numbering tag

The auto-numbering tag automatically generates section numbers based on a formatting string.

Usage: {% n 'formatting_string' %}

Notes: Valid values for the formatting string are "#", "#.#", and "#.#.#"

PaperlexML: {% n '#' %} Important header
{% n '#.#' %} Important sub-header
{% n '#.#' %} More thrilling legal text
{% n '#' %} Another important header
{% n '#.#' %} Less important header
{% n '#.#.#' %} Third-rate legal text
{% n '#.#.#' %} Practically filler text
{% n '#.#.#' %} One more for a good example

Output: 1. Important header
1.1. Important sub-header
1.2. More thrilling legal text
2. Another important header
2.2. Less important header
2.2.1. Third-rate legal text
2.2.2. Practically filler text
2.2.3. One more for a good example

Contracts

Contracts are the cornerstone of the Paperlex API.

GET /contracts.json

Retrieve an array of your contracts

Output: [{"created_at":"2011-10-04T07:09:01Z","uuid":"ce883764523af12e","updated_at":"2011-10-04T07:09:01Z","subject":"NDA"},{"created_at":"2011-10-04T07:09:01Z","uuid":"0694fb3b248c8973","updated_at":"2011-10-04T07:09:01Z","subject":"Pay me"}]
GET /contracts/<contract uuid>.json

Retrieve a contract

AttributeDescription
uuidA unique identifier for this contract
subjectThe subject of this contract
bodyThe PaperlexML that represents the body of this contract
current_versionIs this version of the contract the most current?
lockedIs this contract locked against further edits?
(This will always be true after the contract has been signed by at least one party)
number_of_signersThe number of people who must sign this contract for it to be considered complete
number_of_identity_verificationsThe number of identity verifications a signer must provide to sign the contract
responsesA hash of responses
signersAn array of signers (See Signers for attributes)
signaturesAn array of signatures (See Signatures for attributes)
signature_callback_urlThe URL that Paperlex will POST to when this contract is signed (See Callbacks for more information)
created_atThe date that this contract was created, given as GMT
updated_atThe date that this contract was last updated, given as GMT
Output: {"responses":null,"created_at":"2011-10-04T07:09:01Z","current_version":true,"body":"This Non-Disclosure\tAgreement (the **\"Agreement\"**) is made as of **{{effective_date}}** (the **\"Effective Date\"**) by and between **{{party_a}}**, reachable at **{{party_a_address}}**; and **{{party_b}}**…","uuid":"ce883764523af12e","updated_at":"2011-10-04T07:09:01Z","signers":[{"uuid":"51c442d561291e5b","email":"jhahn@niveon.com"}],"locked":true,"subject":"NDA","number_of_signers":2,"signatures":[{"created_at":"2011-10-05T00:47:18Z","uuid":"7559ad5cb0d36cf2","identity_verification_value":"555-555-1234","identity_verification_method":"SMS"}],"number_of_identity_verifications":1}
GET /contracts/<contract uuid>.html

Retrieve the body of a contract, rendered as HTML

This is the HTML that users will see when they review a contract.

POST /contracts.json

Create a new contract

When creating a contract, only certain attributes are allowed:
AttributeDescription
contract[subject]Required: The subject of this new contract
contract[number_of_signers]Required: The number of people who must sign this new contract for it to be considered complete. Must be an integer greater than zero
contract[responses]A hash of Responses
contract[signature_callback_url]The URL that Paperlex will POST to when this contract is signed (See Callbacks for more information)
contract[body](required if slaw_id isn't present) The PaperlexML that represents the body of this new contract
contract[slaw_id](required if body isn't present) The uuid of a template to create this contract from. If this attribute is provided, the body of this contract is generated from the template, and any passed "body" attribute is ignored

Upon success, the entire new contract is returned.

PUT /contracts/<contract uuid>.json

Update a contract

When updating a contract, only certain attributes are allowed:
AttributeDescription
contract[subject]The subject of this contract
contract[number_of_signers]The number of people who must sign this contract for it to be considered complete. Must be an integer greater than zero
contract[responses]A hash of responses
Note: Passing a responses hash will completely replace existing responses. If you only want to change a single response, use the Responses API
contract[signature_callback_url]The URL that Paperlex will POST to when this contract is signed (See Callbacks for more information)
contract[body]The PaperlexML that represents the body of this contract

Upon success, the entire updated contract is returned.

Concepts: responses, and how the final text of a contract is generated

The final text of a contract is generated by marrying the PaperlexML body with a hash of responses:

contract[body]contract[responses]Final text
This is an agreement between {{party_a}} and {{party_b}}, entered into as of {{effective_date}}. {{party_a}} agrees to pay {{party_b}} the sum of {{loan_amount}} dollars. + party_a: John Smith
party_b: Jane Smith
effective_date: April 1, 2011
loan_amount: 500
= This is an agreement between John Smith and Jane Smith, entered into as of April 1, 2011. John Smith agrees to pay Jane Smith the sum of 500 dollars.

Responses

A contract has many responses. The document processor performs variable substitution.

GET /contracts/<contract uuid>/responses.json

Retrieve an array of responses

Output: {"party_b":"Jane Smith","confidential_duration":"1 year","party_a":"John Smith"}
GET /contracts/<contract uuid>/responses/<key>.json

Retrieve an individual response (by key)

Output: ["John Smith"]
POST /contracts/<contract uuid>/responses.json

Create one or more new responses

You may also use this method to update multiple responses; keys that already exist will be updated with new values.
AttributeDescription
responsesRequired: A hash of responses
Example: responses[party_a]=John%20Smith&responses[party_b]=Jane%20Smith

Upon success, the JSON representation of the new keys and their values is returned.

PUT /contracts/<contract uuid>/responses/<key>.json

Update the value of a response

AttributeDescription
valueRequired: The new value of this response

Upon success, the JSON representation of the value is returned.

DELETE /contracts/<contract uuid>/responses/<key>.json

Delete an individual response

Upon success, the JSON representation of the value is returned.

Concepts: key naming conventions

By following a convention for naming response keys, Paperlex will be able to automatically provide metadata about your contracts:

Key matches…Description
party_a – party_zTreated as parties to the contract (e.g., John Smith)
party_a_address – party_z_addressTreated as addresses of parties to the contract (e.g., johnsmith@example.com)
*_durationTreated as a duration field (e.g., 12 months)
*_dateTreated as a date field (e.g., October 5, 2011)

Signers

Signers are the people who have the ability to sign the contract.

GET /contracts/<contract uuid>/signers.json

Retrieve an array of signers

Output: [{"uuid":"51c442d561291e5b","email":"johnsmith@example.com"},{"uuid":"3ab109b11a083b31","email":"janesmith@example.com"}]
GET /contracts/<contract uuid>/signers/<signer uuid>.json

Retrieve a signer

Output: {"uuid":"3ab109b11a083b31","email":"janesmith@example.com"}
POST /contracts/<contract uuid>/signers.json

Create a new signer

You can only add as many signers as permitted by the "number_of_signers" value.
AttributeDescription
signer[email]Required: The e-mail address of the signer

Upon success, the JSON representation of the signer is returned.

PUT /contracts/<contract uuid>/signers/<signer uuid>.json

Update the attributes of a signer

Again — you can only have as many signers as permitted by the "number_of_signers" value.
AttributeDescription
signer[email]The new e-mail address of the signer

Upon success, the JSON representation of the signer is returned.

DELETE /contracts/<contract uuid>/signers/<signer uuid>.json

Delete a signer

Upon success, the JSON representation of the signer is returned.

Review Sessions

A review session allows someone to review, and optionally sign, a contract.

GET /contracts/<contract uuid>/review_sessions.json

Retrieve an array of review sessions

Output: [{"expires_at":"2011-10-05T07:10:03Z","uuid":"d9df3765905e7695","token":"71fcd58ed9735cad","url":"https://sandbox.api.paperlex.com/v1/contracts/ce883764523af12e/review?token=71fcd58ed9735cad","email":"johnsmith@example.com"}]
GET /contracts/<contract uuid>/review_sessions/<review session uuid>.json

Retrieve a review session

Output: {"expires_at":"2011-10-05T07:10:03Z","uuid":"d9df3765905e7695","token":"71fcd58ed9735cad","url":"https://sandbox.api.paperlex.com/v1/contracts/ce883764523af12e/review?token=71fcd58ed9735cad","email":"johnsmith@example.com"}
POST /contracts/<contract uuid>/review_sessions.json

Create a new review session

AttributeDescription
review_session[email]Required: The e-mail address of the reviewer
review_session[expires_at](optional) What date and time does this review session expire?
(defaults to 24 hours from the current time)
review_session[expires_in](optional) In how many seconds does this review session expire?
Note: Passing this value will take precedence over "expires_at"
(defaults to 24 hours from the current time)

Upon success, the JSON representation of the review session is returned.

PUT /contracts/<contract uuid>/review_sessions/<review session uuid>.json

Update a review session

AttributeDescription
review_session[email]The new e-mail address of the reviewer
review_session[expires_at](optional) What date and time does this review session expire?
(defaults to 24 hours from the current time)
review_session[expires_in](optional) In how many seconds does this review session expire?
Note: Passing this value will take precedence over "expires_at"
(defaults to 24 hours from the current time)

Upon success, the JSON representation of the review session is returned.

DELETE /contracts/<contract uuid>/review_sessions/<review session uuid>.json

Delete a review session

Upon success, the JSON representation of the review session is returned.

Versions

All changes to a contract are versioned. You may view and restore previous versions of contracts.

GET /contracts/<contract uuid>/versions.json

Retrieve an array of versions

Output: [{"version":1,"event":"update"},{"version":2,"event":"update"},{"version":3,"event":"update"}]
GET /contracts/<contract uuid>/versions/<version index>.json

Retrieve the contract as it
existed at the version index

Output: {"responses":null,"created_at":"2011-10-04T07:09:01Z","current_version":false,"body":"This Non-Disclosure\tAgreement (the **\"Agreement\"**) is made as of **{{effective_date}}** (the **\"Effective Date\"**) by and between **{{party_a}}**, reachable at **{{party_a_address}}**; and **{{party_b}}**…","uuid":"ce883764523af12e","updated_at":"2011-10-04T07:09:01Z","subject":"NDA","number_of_signers":2,"number_of_identity_verifications":1}
POST /contracts/<contract uuid>/versions/<version index>/revert.json

Restores the contract as it
existed at the version index

Restoring only creates a new version and marks it as current; it doesn't wipe
revision data for your contract.
Output: {"responses":null,"created_at":"2011-10-04T07:09:01Z","current_version":false,"body":"This Non-Disclosure\tAgreement (the **\"Agreement\"**) is made as of **{{effective_date}}** (the **\"Effective Date\"**) by and between **{{party_a}}**, reachable at **{{party_a_address}}**; and **{{party_b}}**…","uuid":"ce883764523af12e","updated_at":"2011-10-04T07:09:01Z","subject":"NDA","number_of_signers":2,"number_of_identity_verifications":1}

Templates

Templates allow you to create and reuse legal documents that change infrequently. Any changes to a template will not be applied retroactively to contracts that have already been created.

GET /slaws.json

Retrieve an array of your templates

Output: [{"name":"Non-Disclosure Agreement","public":true,"uuid":"23a15b9e18d09168","description":"Non-Disclosure Agreement"}]
GET /slaws/<slaw uuid>.json

Retrieve a template

Output: {"name":"Non-Disclosure Agreement","public":true,"body":"This Non-Disclosure\tAgreement (the **\"Agreement\"**) is made as of **{{effective_date}}** (the **\"Effective Date\"**) by and between **{{party_a}}**, reachable at **{{party_a_address}}**; and **{{party_b}}**…","uuid":"23a15b9e18d09168","description":"Non-Disclosure Agreement","response_keys":["effective_date","party_a","party_a_address","party_b","party_b_address","confidential_duration","state"]}
GET /slaws/<slaw uuid>.html

Retrieve the body of a template, rendered as HTML

You can retrieve an enhanced HTML render by including the attribute "enhanced" with any value. An enhanced HTML render automatically replaces empty responses with the response name.

AttributeDescription
responses[…]An optional hash of responses, allowing you to simulate a contract
An example with responses: https://sandbox.api.paperlex.com/v1/slaws/23a15b9e18d09168.html?token=b53b0c15dce176b4&responses%5Bparty_a%5D=john%20Smith&responses%5Bparty_b%5D=Jane%20Smith
POST /slaws.json

Create a new template

When creating a template, only certain attributes are allowed:
AttributeDescription
slaw[name]Required: The name of this new template
slaw[body]Required: The PaperlexML that represents the body of this new template
slaw[description]A brief description of this new template

Upon success, the entire new template is returned.

PUT /slaws/<template uuid>.json

Update a template

When updating a template, only certain attributes are allowed:
AttributeDescription
slaw[name]The name of this template
slaw[body]The PaperlexML that represents the body of this template
slaw[description]A brief description of this template
DELETE /slaws/<template uuid>.json

Delete a template

Upon success, the JSON representation of the template is returned.

Versions

All changes to a template are versioned. You may view and restore previous versions of templates.

GET /slaws/<template uuid>/versions.json

Retrieve an array of versions

Output: [{"version":1,"event":"update"},{"version":2,"event":"update"},{"version":3,"event":"update"}]
GET /slaws/<template uuid>/versions/<version index>.json

Retrieve the template as it
existed at the version index

Output: {"name":"Non-Disclosure Agreement","public":true,"body":"This Non-Disclosure\tAgreement (the **\"Agreement\"**) is made as of **{{effective_date}}** (the **\"Effective Date\"**) by and between **{{party_a}}**, reachable at **{{party_a_address}}**; and **{{party_b}}**…","uuid":"23a15b9e18d09168","description":"Non-Disclosure Agreement"}
POST /slaws/<template uuid>/versions/<version index>/revert.json

Restores the template as it
existed at the version index

Restoring only creates a new version and marks it as current; it doesn't wipe
revision data for your template.
Output: {"name":"Non-Disclosure Agreement","public":true,"body":"This Non-Disclosure\tAgreement (the **\"Agreement\"**) is made as of **{{effective_date}}** (the **\"Effective Date\"**) by and between **{{party_a}}**, reachable at **{{party_a_address}}**; and **{{party_b}}**…","uuid":"23a15b9e18d09168","description":"Non-Disclosure Agreement"}

Signatures

Signing documents does not occur through API calls. Instead, users are directed to a secure Review Session hosted on Paperlex to review and sign documents. Once a document has been signed, you can GET a contract and examine the signatures attribute for information:

AttributeDescription
uuidA unique identifier for this signature
signer_uuidThe unique identifier of the Signer
identity_verification_methodThe method used by the signer to verify their identity:

email: The signer's e-mail address was verified
sms: The signer's mobile phone number was verified by sending a text message
phone: The signer's phone number was verified by placing an automated call
identity_verification_valueThe signer's verified identity. Either a phone number or e-mail address.
created_atThe date that the signer executed this contract, given as GMT

Callbacks

To keep your application in the loop and prevent polling, Paperlex provides callbacks after important actions occur. These are implemented as HTTP POST requests to your application.

Paperlex requires that your application respond with HTTP status 200 to acknowledge receipt. If the initial callback fails (i.e. returning anything but HTTP status 200), Paperlex will attempt to POST a callback to your application every 5 + (n ** 4) seconds, where n is the number of retries, until your application responds with HTTP status 200. After 25 failed attempts, we will stop sending the callback. You may replay callbacks from the "Callbacks" tab of the Control Panel.

A final note: callbacks need to be handled quickly. Your application must take no more than 2 seconds to process a callback.

Testing Callbacks

POST /callbacks/ping.json

Ping a callback URL

AttributeDescription
urlRequired: The URL to ping

Use this function to test your callback URLs. Paperlex will make an HTTP POST request to the provided url.

If your application responds with HTTP status 200, ["OK"] will be returned. Otherwise, ["FAILURE"] will be returned.

signature

Sent after a user signs a contract. These attributes will be provided:

AttributeDescription
typesignature
contract_uuidThe unique identifier of the Contract that was signed
signature_uuidThe unique identifier of the Signature
signer_uuidThe unique identifier of the Signer
identity_verification_methodThe method used by the signer to verify their identity:

email: The signer's e-mail address was verified
sms: The signer's mobile phone number was verified by sending a text message
phone: The signer's phone number was verified by placing an automated call
identity_verification_valueThe signer's verified identity. Either a phone number or e-mail address.
created_atThe date that the signer executed this contract, given as GMT

contract.slaw_updated

Sent when the contract's Template is updated. These attributes will be provided:

AttributeDescription
typecontract.slaw_updated
contract_uuidThe unique identifier of the Contract

Examples: You may want to limit a user's abilities until they review then new contract or send them an email prompting them to review and agree to the new contract.

Simple Signatures

Simple Signatures allows you to rapidly collect signatures for routine contracts with a single signer. Popular examples incldue rental agreements, software license agreements, and NDAs. Instead of fully integrating with the Paperlex API, you simply POST to a special URL; we handle the signature process and POST back to your application, passing data about the signed contract.

Important note: remember to use your Simple Signatures API token!

Request Signature

POST /simple_signatures.html

Collect a simple signature

AttributeDescription
public_tokenRequired: Your public Simple Signatures API token
return_urlRequired: The URL the user will be returned to after signing. This URL should also be able to accept POST requests that contain callback data
slaw_idRequired: The UUID of a Template used to create the displayed contract
responses[…]Required: A hash of Responses
emailRequired: The e-mail address of the signer
sensor(optional) Does the device being used to sign the contract contain a touchscreen and GPS sensor? Examples include iPad and iPhone. Providing a value of "true" will allow the user to sign by affixing a virtual signature and attaching their GPS location. Default value is false

Upon a successful signature, Paperlex will POST the equivalent of a Signature callback to your return_url.