API Developers Guide

Getting Started

MyWhistleBox provides developers a path to integrate their applications to the MyWhistleBox service through an Application Programming Interface (API). This is a great way to extend the MyWhistleBox service using an existing workflow.

Here are a just a few examples of things you can do with the REST API:
  • Schedule batch uploads of documents to user accounts
  • Integrate Signature and Upload Requests into an existing CRM workflow
  • Develop a custom user interface to the WhistleBox server
  • Schedule the downloading of reports to a Sharepoint server
The MyWhistleBox API is implemented using a REST model and requires an Enterprise plan. The REST model uses standard HTTP requests to communicate with the MyWhistleBox API service. Developers can use any programming language that support standard HTTP request calls. A public PHP wrapper is available on github located at https://github.com/mywhistlebox/mwb-php. Although the wrapper makes things a bit easier to implement using PHP, any HTTP library like cURL can be used to make requests and handle return values.

How to Access the REST Service

To access a REST endpoint via the service, construct a URL using the base endpoint along with an action suffix described below. The base endpoint for the REST service is https://mywhistlebox.com/api/rest/v1.0/.

Authentication

MyWhistleBox uses a simple API Key for authentication. All requests must contain a valid API key. You simply make an HTTP Request by including the following header:

"Authorization: <apikey>"

The "apikey" can be generated and copied from your MyWhistleBox Account Settings API Tab (see Configuration Guide).

Requesting an Endpoint

The endpoints (actions) below are described using the following form:


[GET | POST | DELETE] /{action}/<optional parameters>
Summary:
Content-Type: application/x-www-form-urlencoded OR multipart/form-data 

Request Body {
    <param> : value,
    key: value,
    ......
}

Responses 
    200 OK: {
    {
        status: "ok",
        key: object,
        key: value,
        ....
    }
                        
Content-Type: application/x-www-form-urlencoded is assumed unless noted.

For example, a generic request would look like:

https://mywhistlebox.com/api/rest/v1.0/{action}/<params>

e.g. To list the boxes in your account (no params required).

Send a http request with the GET method type along with the Authorization header and url:

https://mywhistlebox.com/api/rest/v1.0/list/boxes

The action's response (if any) will be decribed in the Response portion.

To make integrating easier, we offer a php api sdk library. Instructions are included with the sdk. You can also use any request mechanism your language offers including cURL. If you want to use cURL, check out the cURL example document on the developer home page.

Ping Test

To get familiar with using the endpoints, we provide a test endpoint called /test/ping. You can use this endpoint to determine if your authentication process is working and your request is reaching the REST server. If the response is “ok”, your request has reached the service and your APIKey has been authorized.

Date Inputs

Some endpoints require Date or Date/Time inputs. These values should be formatted following the ISO 8601 format. An example of a date parameter is:


{
    "date_start": "2015-08-12"
}
                        

Errors

In addition to the Responses noted for each endpoint, all endpoints can receive an error Response in the following form:


{
    status: "error",
    code: <error code string>,
    message: <error message string>
}
                        
If you receive an Access Denied error, this typically mean the APIKey can't be validated (due to typos or revocation), or the account lacks API access. If you are sure your request is formatted properly, check to make sure you copied and pasted the API key correctly. Keys shouldn't contain any spaces.

Webhooks

External processes can register a webhook to fire when certain events occur within MyWhistleBox. This eliminates the need for polling. A webhook registration is comprised of an event type, a url and an optional filter. When the event occurs, MyWhistleBox will "call back" the provided url with event information. This information can be used by the external process to perform some action.

Webhook Events
  • file.upload
    • Fires when a new file is uploaded to the account.
  • memo.upload
    • Fires when a new Note (memo) is uploaded to the account.
  • memo.update
    • Fires when a Note (memo) is updated.
Filters
Filters are an optional json structure included with the request used to limit event firings to certain conditions. The same thing can be achieved on the receiving end by inspecting the fired event properties. Filters should be in the following structure:

        {
            default : {
                // default file.upload event properties
                file_upload_public : true | false,
                file_upload_private : true | false,
                file_signed : true | false,
                // default memo.upload and memo.update event properties
                memo_upload_public : true | false,
                memo_upload_private : true | false,
            },
            boxes : {
                '<box1>' : {/* event properties */  },
                '<box2>' : {/* event properties */  }
                .....
            }
        }
                        
Rules
  1. If no filter is provided in the request, all events will be fired.
  2. The default value for event properties is indicated in bold.
  3. Properties included in the default key will override default event properties.
  4. Boxes included in the boxes key will be monitored.
  5. Any optional properties included with a box will override the default settings.
  6. Public means created via a request (e.g. Upload or WhistlePage). Private means created via a user from within MyWhistleBox.
Event Properties
When the webhook url is called, it will include the following event properties.
  • event
  • id
  • boxId
  • boxName
  • public
  • filePath (file events)
  • fileName (file events)
  • fileSize (file events)
  • fileMime (file events)
  • fileSubject (file events)
  • fileSender (file events)
  • memoTitle (memo events)
  • memoText (memo events)
  • created
  • modified (memo events)

Endpoint (Actions)

Actions are grouped into categories. To query certain resources, it may be necessary to query more than one endpoint. For example, /file/info requires a "file_id". You could first use the /list/files endpoint to obtain the desired file_id and then use that id with the /file/info endpoint. A list of endpoints by Category are:

List
  • GET /list/boxes
  • GET /list/pages
  • GET /list/folders/<parent_id>
  • GET /list/files/<folder_id>
  • GET /list/memos/<folder_id>
  • GET /list/templates
User
  • POST /user/file/upload
  • POST /user/file/uploadUrl
  • POST /user/memo/upload
  • POST /user/file/send/<file_id>
  • POST /user/file/sendsign/<file_id>
Folder
  • POST /folder/upload/<folder_id>
  • POST /folder/uploadUrl/<folder_id>
  • POST /folder/<parent_id>
File
  • GET /file/info/<file_id>
  • GET /file/download/<file_id>
  • POST /file/search
Memo (Personal Notes)
  • GET /memo/<memo_id>
  • POST /memo/<folder_id>
Request
  • POST /request/upload/<box_id>
  • POST /request/whistlepage/<page_id>
  • POST /request/signature/<file_id>
  • POST /request/download/<file_id>
Report
  • POST /report/log/upload
  • POST /report/log/whistlepage
  • POST /report/log/download
  • POST /report/log/signature
  • POST /report/log/sender
  • POST /report/log/audit
Webhooks
  • POST /webhook
  • DELETE /webhook/<id>
Test
  • GET /test/ping
Use these category tabs to obtain more details of each endpoint.

GET /list/boxes
Summary: List all boxes for this account.

Request Body {
}

Responses 
    200 OK: {
        status: "ok",
        boxes: [{
            id: box id,
            name: box name
        }],
        defaultBoxId: default box id
    }
                                
GET /list/pages
Summary: List all WhistlePages for this account.

Request Body {
}

Responses 
    200 OK: {
        status: "ok",
        pages: [{
            id: whistlepage id,
            name: whistlepage name
        }] 
    }
                                
GET /list/folders/<parent_id>
Summary: List all first level child folders in specified box or folder.

Request Body {
    <parent_id>: id of the parent folder [required]
}

Responses 
    200 OK: {
        status: "ok",
        folders: [{
            id: folder id,
            name: folder name
        }] 
    }
                                
GET /list/files/<folder_id>
Summary: List all files in specified box or folder.

Request Body {
    <folder_id>: id of the folder files reside in [required]
}

Responses 
    200 OK: {
        status: "ok",
        files: [{
            id: file id,
            name: file name
        }] 
    }
                                
GET /list/memos/<folder_id>
Summary: List all memos (personal notes) in specified memo folder.

Request Body {
    <folder_id>: id of the memo folder [required]
}

Responses 
    200 OK: {
        status: "ok",
        memos: [{
            id: memo id,
            title: memo title
        }]
    }
                                
GET /list/templates
Summary: List all Signature Templates for this account.

Request Body {
}

Responses 
    200 OK: {
        status: "ok",
        files: [{
            id: template file id,
            name: template file name
        }]
    }
                                
POST /user/file/upload
Summary: Upload file contents to a users box.

Content-Type: multipart/form-data

Request Body {
    address: WhistleBox address string of user, [required]
    file: form-data formatted file contents, [required]
    confirmEmail: email for confirmation,
    subject: subject of the file,
    note: note attached to the uploaded file,
}

Responses 
    200 OK: {
        status: "ok",
        id: id of the new uploaded file
    }
                                
POST /user/file/uploadUrl
Summary: Upload a file to a users box using the file url.

Request Body {
    address: WhistleBox address string of user, [required]
    fileUrl: file path string to the remote file to be uploaded, [required]
    fileName: optional file name to override the fileUrl name,
    confirmEmail: email for confirmation,
    subject: subject of the file,
    note: note attached to the uploaded file,
}

Responses 
    200 OK: {
        status: "ok",
        id: id of the new uploaded file
    }
                                
POST /user/memo/upload
Summary: upload a personal note to a users box

Request Body {
    address: WhistleBox address string of user, [required]
    title: title of the memo, [required]
    text: memo text [required]
}

Responses 
    200 OK: {
        status: "ok",
        id: id of the new memo
    }
                                
POST /user/file/send/<file_id>
Summary: send an account file to a users box

Request Body {
    <file_id>: optional id of the file to be sent,
    file_ids: comma separated list of file_ids, [required?]
    address: WhistleBox address of user, [required]
    confirmEmail: email for confirmation,
    note: note attached to the uploaded file
}

Responses 
    200 OK: {
        status: "ok",
        fileCount: number of files sent,
        to: recipient address,
        sentStatus: [{
            id: file id,
            file: file name,
            result: result of send
        }] 
    }
                                
POST /user/file/sendsign/<file_id>
Summary: send an account file to a users box for signature

Request Body {
    <file_id>: id of the file to be sent [required]
    address: WhistleBox address of user, [required]
    template_id: id of a signature template
    note: note attached to the uploaded file
}

Responses 
    200 OK: {
        status: "ok",
        to: recipient address,
        sentStatus: {
            id: file id,
            file: file name,
            result: result of send
        } 
    }
                                
Note: If <file_id> is omitted, file_ids are required
POST /folder/upload/<folder_id>
Summary: direct upload a file contents to our folder

Content-Type: multipart/form-data

Request Body {
    <folder_id>: our target folder id [required]
    file: form-data formatted file to the local file to be uploaded [required]
}

Responses 
    200 OK: {
        status: "ok",
        id: id of the new file
    }
                                
POST /folder/uploadUrl/<folder_id>
Summary: direct upload a file via URL to our folder

Request Body {
    <folder_id>: our target folder id [required]
    fileUrl: file path string to the remote file to be uploaded [required]
    fileName: optional file name to override the fileUrl name,
}

Responses 
    200 OK: {
        status: "ok",
        id: id of the new file
    }
                                
POST /folder/<parent_id>
Summary: Create a new folder in parent

Request Body {
    <parent_id>: id of the parent folder we want to create in [required]
    name: name of folder to be created [required]
}

Responses 
    200 OK: {
        status: "ok",
        id: id of the new folder
    }
                                
GET /file/info/<file_id>
Summary: get a file's metadata

Request Body {
    <file_id>: id of target file [required]
}

Responses 
    200 OK: {
        status: "ok",
        file: {
            id: file id,
            name: file name,
            size: size in bytes,
            mimeType: file mime type,
            senderName: name of person who uploaded,
            company: sender company,
            subject: subject of file,
            notes: file note,
            confirmed: has this file been confirmed received?,
            unread: has this file been unread?,
            signed: is this file signed?,
            created: created date (gmt),
            modified: modified date (gmt)
        }
    }
                            
GET /file/download/<file_id>
Summary: download a file

Request Body {
    <file_id>: id of target file [required]
}

Response: Full file contents. File name and mime type included in http response header.  Typically response content should be 
saved to a local file with the name specified in the header.
                            
POST /file/search
Summary: search account for files

Request Body {
    srchName: file name (default ''),
    srchSubject: file subject (default ''),
    srchSender: file sender (default ''),
    srchDateFrom: file Date From  (default ''),
    srchDateTo: file Date To (default ''. If not '', file date is range DateFrom to DateTo),
    srchUnread: Search Unread files (0 or 1 default 0),
    srchSigned: Search for Signed Files (0 or 1 default 0),
    srchTrash: Search Trash (0 or 1 default 0),
    srchWhistlePage: Search for Include WhistlePage (0 or 1 default 0),
    srchTemplates: Search for Signature Template (0 or 1 default 0)
}

Responses 
    200 OK: {
        status: "ok",
        file: [{
            id: file id,
            folderId: folder id,
            boxId: box id,
            path: file path (from box),
            name: file name,
            size: size in bytes,
            mimeType: file mime type,
            senderName: name of person who uploaded,
            company: sender company,
            subject: subject of file,
            notes: file note,
            confirmed: has this file been confirmed received?,
            unread: has this file been unread?,
            signed: is this file signed?,
            signatureTemplate: is this a signature template?,
            pageLinked: is available in WhistlePages?,
            created: created date (gmt),
        }]
    }
                            
GET /memo/<memo_id>
Summary: fetch a memo

Request Body {
    <memo_id>: id of memo [required]
}

Responses 
    200 OK: {
        status: "ok",
        memo: {
            id: memo id,
            title: memo title,
            text: memo contents,
            created: created date (gmt),
            modified: modified date (gmt)
        }
    }
                                
POST /memo/<folder_id>
Summary: create a new memo

Request Body {
    <folder_id>: memo folder id [required],
    title: memo title string [required],
    text: memo text string [required]
}

Responses 
    200 OK: {
        status: "ok",
        id: memo id
    }                           
                                
POST /request/upload/<box_id>
Summary: email an upload request

Request Body {
    <box_id>: id of the upload target box [required]
    email: email address of recipient [required]
    expireDays: how many days before email link expires (0-14)
    note: note to be included with email body
}

Responses 
    200 OK: {
        status: "ok"
    }
                                
POST /request/whistlepage/<page_id>
Summary: email a whistlePage request

Request Body {
    <page_id>: id of the page to be requested [required]
    email: email address of recipient [required]
    expireDays: how many days before email link expires (0-14)
    note: note to be included with email body
}

Responses 
    200 OK: {
        status: "ok"
    }
                                
POST /request/signature/<file_id>
Summary: email a signature request

Request Body {
    <file_id>: optional id of the file to be signed
    file_ids: comma separated list of file_ids [required?]
    email: email address of recipient [required]
    accessType: Security type required of signor [required]
    accessCode: security code signor must enter [required?]
    expireDays: how many days before email link expires (1-14)
    template_id: id of a template file used to apply to the signature document
    note: note to be included with email body
}

Responses 
    200 OK: {
        status: "ok"
    }
                                
Notes:
  1. If <file_id> is omitted, file_ids are required
  2. accessType: 'NONE', 'SSN4', 'SSN5', 'ZIP5', 'PHONE4', 'CUSTOM'
  3. accessCode is required if accessType is not NONE.
POST /request/download/<file_id>
Summary: email a download request

Request Body {
    <file_id>: optional id of the file to be signed,
    file_ids: comma separated list of file_ids [required?],
    email: email address of recipient [required],
    accessType: Security type required of signor [required],
    accessCode: security code signor must enter [required?],
    expireDays: how many days before email link expires (1-14),
    note: note to be included with email body
}

Responses 
    200 OK: {
        status: "ok"
    }
                                
Notes:
  1. If <file_id> is omitted, file_ids are required
  2. accessType: 'NONE', 'SSN4', 'SSN5', 'ZIP5', 'PHONE4', 'CUSTOM'
  3. accessCode is required if accessType is not NONE.
POST /report/log/upload
Summary: generate upload request log report. For large reports, can be called repeatedly to get record sets.

Request Body {
    startDate: report period start (YYYY-MM-DD) [required],
    endDate: report period end (YYYY-MM-DD) [required],
    limit: max records to return (default 5000),
    startAt: start record number(default 0)
}

Responses 
    200 OK: {
        status: "ok",
        entries: [{
            folderId: box id,
            folderName: box name,
            email: recipient's email,
            status: request status,
            expires: expiration date,
            created: created date
        }],
        count: number of records returned in this set,
        total: total records in report,
        next: record number beginning of next set (-1 if last set)
    }
                                
Notes: If total records is greater than the limit, startAt can be used in successive calls by using returned "next" value to retrieve the next set of records.

POST /report/log/whistlepage
Summary: generate WhistlePage request log report. For large reports, can be called repeatedly to get record sets.

Request Body {
    startDate: report period start (YYYY-MM-DD) [required]
    endDate: report period end (YYYY-MM-DD) [required]
    limit: max records to return (default 5000)
    startAt: start record number(default 0)
}

Responses 
    200 OK: {
        status: "ok",
        entries: [{
            pageId: whistlepage id,
            pageName: whistlepage name,
            email: recipient's email,
            status: request status,
            expires: expiration date,
            created: created date
        }],
        count: number of records returned in this set,
        total: total records in report,
        next: record number beginning of next set (-1 if last set)
    }
                                
Notes: If total records is greater than the limit, startAt can be used in successive calls by using returned "next" value to retrieve the next set of records.

POST /report/log/download
Summary: generate download request log report. For large reports, can be called repeatedly to get record sets.

Request Body {
    startDate: report period start (YYYY-MM-DD) [required]
    endDate: report period end (YYYY-MM-DD) [required]
    limit: max records to return (default 5000)
    startAt: start record number(default 0)
}
Responses 
    200 OK: {
        status: "ok",
        entries: [{
            fileId: file id,
            fileName: filename,
            accessType: security access type,
            accessCode: security access code,
            email: recipient's email,
            status: request status,
            expires: expiration date,
            created: created date
        }],
        count: number of records returned in this set,
        total: total records in report,
        next: record number beginning of next set (-1 if last set)
    }
                                
Notes: If total records is greater than the limit, startAt can be used in successive calls by using returned "next" value to retrieve the next set of records.

POST /report/log/signature
Summary: generate signature request log report. For large reports, can be called repeatedly to get record sets.

Request Body {
    startDate: report period start (YYYY-MM-DD) [required]
    endDate: report period end (YYYY-MM-DD) [required]
    limit: max records to return (default 5000)
    startAt: start record number(default 0)
}

Responses 
    200 OK: {
        status: "ok",
        entries: [{
            fileId: file id,
            fileName: filename,
            accessType: security access type,
            accessCode: security access code,
            email: recipient's email,
            status: request status,
            expires: expiration date,
            created: created date
        }],
        count: number of records returned in this set,
        total: total records in report,
        next: record number beginning of next set (-1 if last set)
    }
                                
Notes: If total records is greater than the limit, startAt can be used in successive calls by using returned "next" value to retrieve the next set of records.

POST /report/log/sender
Summary: generate sender log report. For large reports, can be called repeatedly to get record sets.

Request Body {
    startDate: report period start (YYYY-MM-DD) [required]
    endDate: report period end (YYYY-MM-DD) [required]
    limit: max records to return (default 5000)
    startAt: start record number(default 0)
}

Responses 
    200 OK: {
        status: "ok",
        entries: [{
            wbAddress: whistlebox address,
            fileId: file id,
            fileName: file name,
            folderName: box name,
            signRequest: is a signature requested?,
            expires: signing request expiration date,
            downloaded: has signed document been accessed?,
            confirmRequest: is a confirmation requested?,
            Confirmed: has this file been confirmed?,
            created: sent date
        }],
        count: number of records returned in this set,
        total: total records in report,
        next: record number beginning of next set (-1 if last set)
    }
                                
Notes: If total records is greater than the limit, startAt can be used in successive calls by using returned "next" value to retrieve the next set of records.

POST /report/log/audit
Summary: generate audit log report. For large reports, can be called repeatedly to get record sets.

Request Body {
    startDate: report period start (YYYY-MM-DD) [required]
    endDate: report period end (YYYY-MM-DD) [required]
    limit: max records to return (default 5000)
    startAt: start record number(default 0)
}

Responses 
    200 OK: {
        status: "ok",
        entries: [{
            userName: name of user ,
            action: what was done,
            on: object of the action,
            to: result of the action,
            created: action date     
        }],
        count: number of records returned in this set,
        total: total records in report,
        next: record number beginning of next set (-1 if last set)
    }
                                
Notes: If total records is greater than the limit, startAt can be used in successive calls by using returned "next" value to retrieve the next set of records.
GET /test/ping
Summary: test your APIKEY connection

Request Body {
}

Responses 
    200 OK: {
        status: "ok"
    }
                                
POST /webhook
Summary: Register a webhook.

Request Body {
    event: Event to be triggered (see webhook section) [required],
    url: URL to be called on the event [required],
    filters: An optional filter (see webhook section),
}

Responses 
    200 OK: {
        status: "ok"
        id: id of the registered webhook
    }
                                
DELETE /webhook/<id>
Summary: Destroy a webhook registration.

Request Body {
}

Responses 
    200 OK: {
        status: "ok"
    }