NAV
Last Bill
cURL

Introduction

TODO: Add some welcome here.

Format

Request

json data

curl "https://www.lastbill.com/api/some.json" \
-H "Content-Type: application/json" \
-X POST -d '{"param1":"one","param2":"two"}'

x-www-form-urlencoded

curl "https://www.lastbill.com/api/some.json?\
param1=one&param2=two" \
-H "Content-Type: application/x-www-form-urlencoded" \
-X POST

form-data

curl "https://www.lastbill.com/api/some.json" \
-H "Content-Type: multipart/form-data" \
-X POST \
-F 'param1=one' \
-F 'param2=two'

Our server accepts requests:

Make sure to add corresponding "Content-Type" header. e.g.:

Content-Type: application/json

Response

.json suffix

curl "https://www.lastbill.com/api/some.json \
-X GET

accept any format header

curl "https://www.lastbill.com/api/some \
-X GET -H "Accept: */*"

accept JSON header

curl "https://www.lastbill.com/api/some \
-X GET -H "Accept: application/json"

x-www-form-urlencoded

curl "https://www.lastbill.com/api/some?format=json" \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded"

form-data

curl "https://www.lastbill.com/api/some" \
-X POST \
-F 'format=json' \
-H "Content-Type: multipart/form-data"

We serve JSON in response. In order to receive a correct response one should add any of the following options:

  1. ".json" suffix to the url
  2. Header to accept anything "*/*"
  3. Header to accept JSON "application/json"
  4. url-encoded param format=json
  5. form-data param format=json

Lists

Our index (list) endpoints share common rules. This ensures all lists look&feel the same, no matter what they list: users or nuclear missiles.

Request

Request params for list

curl "https://www.lastbill.com/api/users.json\
?page=1&per_page=25&order_field=email\
&filter[query]=John"

We accept the following input params:

key default description
page 1 string or integer
Current page
per_page 12 string or integer
How many results to show in the page.
Maximum is limited to 100.
filter {} hash
List of allowed filter options. List endpoints should provide description for them.
order_field id string
Order field for relation. List endpoints contain a valid list of fields that can be used to order. id might not be a default for most of them, however, it is the only field that is always present and allowed in our relations.
order_direction asc string
"asc" or "desc" are the only values allowed. Anything else here is applied to the relation as "asc".

Response

Response example

{
  "meta": {
    "total_pages": 3,
    "total_count": 54,
    "page": 1,
    "per_page": 25,
    "filter": { "query": "John" },
    "order_field": "email",
    "order_direction": "asc"
  },
  "data": [
    { "id": 123, "email": "john.doe@example.com", ... },
    ...
  ]
}

Output params:

key description
data array
Result list
meta hash
Object with list details. See below.
meta[total_pages] integer
Number of pages for relation
meta[total_count] integer
Total number of results
meta[page] See input params
meta[per_page] See input params
meta[filter] See input params
meta[order_field] See input params
meta[order_direction] See input params

Locale

We support locales:

Force locale for request

User locale we use for responses is taken from authenticated user account settings. But sometimes we need to force the locale of the endpoint or specify it for user-less endpoints like Login. It is possible to do via locale param. Pass it to any request and it will force the locale to passed in params value.

POST /api/login.json?locale=fr

key description
locale string
Locale for response of current request.

Errors

Most common error format is String

{ "message": "some error", "error": "some_short_code" }

In case of many errors result they are passed as an Array

{ "message": [ "i'm first error", "i'm second one" ], "error": "some_short_code" }

Error response is an Object with "error" message. The message should be descriptive enough to buy what happened.

{ "message": "message", "error": "error_code" }

In case of many errors you might receive an "error" array:

{ "message": ["message", "message", ...], "error": "error_code" }

Common errors you might face are described here:

http code error code status description
400 bad_request Bad Request Request is missing required values or is impossible to parse.
Say, when we require user[login] param in request, but lack it. Or if JSON body of the request is not valid, e.g. {incorrect:"json"}.
401 unauthorized Unauthorized Request is missing an API token header Authorization: some-api-token or the token is invalid.
403 forbidden Forbidden Request lacks privileges to be executed. E.g. your user lacks private api token in login, or user account is disabled.
404 page_not_found Not Found Requested endpoint or resource is not found in our server.
503 service_unavailable Service Unavailable Our app is down for maintenance.
5XX internal_server_error Internal Server Error Something bad (we have no clue about) happened. But don't be afraid - we are working on the solution 😇

Date & Time

API responses always contain UNIX datetime for any date, time and datetime value types.

You have to extract time or date from datetime value. E.g. time value 14h30 will be returned as any date with 14:30 time: 1596119400000.

Phone number

Our endpoints require phone numbers to have international format with country code. E.g. +375-12-345-67-89, where 375 is the country code. This ensures SMS messages are correctly delivered.

We store only numbers, so input phone format may be any. In response we return non-formatted numbers.
Returned phone number data type is integer.

input we store and send in response
+33 01 83 62 50 20 330183625020
+330183625020 330183625020
330183625020 330183625020
+33(01)-83-62-50-20 330183625020

Location

We use CSV lat,lon format for locations. That is the way we store locations in the DB, workflow's JSON and return back in responses.

Example of Paris location:
48.856181,2.3519511

However, in your requests you may use more formats:

  1. Primary location format lat,lon CSV string.
  2. Same as nr.1, but enclosed in brackets: (lat,lon).
  3. Hash (object) format:
    1. { "x": 1, "y": 1 }, where x is the latitude, y is the longitude.
    2. { "lat": 1, "lon": 1 } n/c.
    3. { "lat": 1, "lng": 1 } same as previous, but with other longitude abbreviation.

Workflows

Simplest possible correct workflow:

{
    "type": "workflow",
    "uuid": "1",
    "children": [
      {
        "type": "template_job_info",
        "uuid": "2"
      }
    ]
}

Workflow is a nested json structure that describes job steps and it's controls. We call smallest workflow element a cell.

Every cell has a type, uuid and children(optional) :

  1. type allows to determine a cell class. This attribute is the only one required every time.
  2. uuid is a unique reference of the cell within the workflow.
  3. children is an array of descendant(nested) cells that allows us to nest cells and build beautiful workflow trees.

We distinguish 5 main types of cells:

Workflow commandments

  1. Each cell uuid should be unique per Workflow
  2. Templates are only nested directly in a Workflow
  3. Workflow requires at least one Template
  4. First template is TemplateJobInfo
  5. TemplateJobInfo is single
  6. TemplateBlank requires at least one child
  7. Sections are only nested directly in a Template
  8. Section requires at least one child
  9. Groups are only nested directly in a Section
  10. Group requires at least one child
  11. Group has no label and styles
  12. Widgets are only nested directly in a Section or Group
  13. Widgets can't have children

Templates

Template is a workflow step and a workflow is a set of templates after all. Each job is going to be split to a list of templates that are passed one by one by the performer. The same applies to the send job functionality.

Template Job Information

Cell type template_job_info

Template job information is required template that is always present and always first step of any job. It is very much similar to Template Blank, but contains required section with Job Title, Job Reference, Due Date, Work Order Address. The data from them goes directly to job record and is available in job list to view/filter.

Template Blank

Cell type template_blank

Blank template is a constuctor where you can visualize your workflow needs. With help of group elements (sections and groups) and a set of widgets you may create a workflow of your dream.

Before adding widgets you should add a section(s) to template. Also groups may nest widgets. Groups should be added to sections only. The allowed structure is: Section => Widget or Section => Group => Widget. Sections and Groups are deeper explained in corresponding articles.

Template Invoicing

Cell type template_invoicing

This is common implementation of invoice model for jobs. It allows performer to enter * invoice name * reference number * amount netto (VAT excluded) * amount brutto (VAT included) * attach an invoice document (pdf, image, photo, etc.)

When configuring/sending the template it is possible to chose currency (EUR is default).

Template Navigation

Cell type template_navigation

Navigation is a common pattern to track performer movements between job locations. It allows: 1. Performance tracking 1. Notify performer with exact client location (if client receives and follows special link from our app). 1. Notify client when performer is gonna come 1. Show performer location/moves to client when travelling to client.

TODO: extend documentation

Template Photo

Cell type template_photo

Photo template is required to collect some photos from performer. Photo template preceded with navigation makes an unbeatable combo: drive to some location + take photos there. Sender may configure required photo count and describe what photos should focus on.

Template Signature

Cell type template_signature

Signature template requires client to read and accept Terms and Conditions.

Template Time Tracking

TODO: document me

Widgets

TODO: document me

Sections

TODO: document me

Groups

TODO: document me

Workflow Attributes

A bit more complicated example:

{
  "workflow": {
    "type": "workflow",
    "uuid": "aa3b7f9d-d23b-4659-982a-6023be440e6f",
    "children": [
      {
        "type": "template_job_info",
        "uuid": "b069d74e-2f7f-466f-ac67-ce12ac6e1506",
        "label": "Job Summary",
        "job_title": "asd",
        "children": [
          {
            "type": "section",
            "uuid": "25fe629d-ea92-4ec4-8e9d-175e502899eb",
            "label": "Section",
            "direction": "col",
            "children": [
              {
                "type": "widget_text",
                "uuid": "0be96ba5-7fb9-4aad-8c1b-7427cc282e1f",
                "label": "First Name",
                "data": "first",
                "data_type": "string",
                "access": 3
              },
              {
                "type": "widget_text",
                "uuid": "2bdefcd7-4e37-4da2-913b-5e1a545cfb98",
                "label": "Last Name",
                "data": "second",
                "data_type": "string",
                "access": 3
              },
              {
                "type": "widget_select",
                "uuid": "ddd51528-719e-4900-a8d9-69feddc6ee87",
                "label": "Select Multiple",
                "data": [
                  "option 1"
                ],
                "data_type": "checkbox",
                "access": 3,
                "options_list": [
                  "option 1",
                  "option 2"
                ],
                "multiple": true
              }
            ]
          }
        ]
      },
      {
        "type": "template_blank",
        "uuid": "56987c0d-a265-4900-aca0-482b61298e29",
        "label": "Blank",
        "children": [
          {
            "type": "section",
            "uuid": "a5bf9c4d-40b8-427d-af49-ab8ea11cc354",
            "direction": "col",
            "children": [
              {
                "type": "widget_text",
                "uuid": "8762269f-eff1-47a8-92cb-119956bac4f5",
                "label": "Label",
                "data": "asd",
                "data_type": "string"
              }
            ]
          }
        ]
      },
      {
        "type": "template_navigation",
        "uuid": "df2f25b2-6dd8-40fc-9487-900cc000ab4c",
        "label": "Navigation",
        "performer_notifications": true
      }
    ]
  }
}
cell type attribute default description
any type class.type_name Required field.
It represents cell class name in snake case without jobs module prefix.
:type is a cell_class.model_name.element. E.g.
Jobs::TemplateBlank.model_name.element => "template_blank"
any uuid SecureRandom.uuid * Required field
It represents unique reference of the cell inside a workflow.
If not passed this field is generated automatically on object instantiation
any children Children store child cell of a current cell.
any label Most common visual attribute. You will see it everywhere: it represents name of template, section and widget.
any access 111 for sections, groups, templates
133 for widget
integer
See access section.
section, group direction col How to visually stack widgets:
Column mode means fields are stacked in a column one below another.
Row mode means in mid screen sizes and more fields may be cols of the same row.
any template label Translated template name Required field
any template completed false This field marks template as ready when sending a job or performing a job. It may be set in the workflow, but before and after job send this completed state is reset.
any template completed_at That field is set the timestamp when performer updates the template and it is marked as completed.
any template completed_location That field is set the location of performer when he updates the template and it is marked as completed.
template_job_info job_title Job's title.
template_job_info job_reference Job's reference.
template_job_info job_due_date Job's due date.
template_job_info job_address Job's work order address.
template_job_info job_location Job's work order address geocoded location.
template_invoicing currency EUR Required field
Valid currency code from list
  • EUR
  • USD
.
template_invoicing title Invoice title.
template_invoicing number Invoice reference number.
template_invoicing amount_netto Invoice amount netto (VAT excluded).
template_invoicing amount_brutto Invoice amount brutto (VAT included).
template_navigation address Destination address.
template_navigation location Geo-coded location for destination address.
template_navigation details Destination address details.
template_navigation performance_review false Enables performance review for job.
template_navigation client_notifications false Allows client to receive link with performer route and ability to track performer.
template_navigation client_phone Mobile phone number for #client_notifications.
template_navigation client_notify_in Notify client in X minutes/hours before performer comes.
template_navigation client_notify_unit m Required field
Unit for #client_notify_in option. Valid values: m for minute, h for hour.
template_navigation performer_notifications false Allows performer to see client's location
template_navigation performer_phone Performer phone number.
template_navigation started false Indicates if performer started navigation. Set automatically as soon as performer sends his location to template.
template_photo photo_count 1 Required photo count. Minimum is 1 photo.
template_photo description Describe what kind of photos required.
template_signature terms Required field
Terms and conditions client should accept and sign.
section, any widget color Font color to represent value (or label for sections).
Valid format is string #hhh or #hhhhhh, where h is a hex number.
E.g. #f4a
section, any widget bold false Font bold to represent value (or label for sections).
section, any widget italic false Font italic to represent value (or label for sections).
any widget data_type data_types.first Required field
Represents a specific data visualization and behavior (cast).
any widget label Required field
any widget reference Indexed value that goes to job_datum model and allows building data statistic.
any widget data Allows to store some datum to the workflow before we send a job.
any widget full_width false Makes widget obtain full space of the row despite what option is provided in the container.
widget_select options_list Required field
Valid values list.
widget_select multiple Allow multiple values selection.
widget_address address Address.
widget_address location Geo-coded location for address. E.g. 23.234,43.554.
widget_address show_map true Option to show map for address(location).
widget_file data_type any Required field
Valid list of values:
  • image
  • document
  • media
  • any

Access and contexts

Every cell has access attribute. Access describes if the cell is readable, writable and required. Each access type we call access bit and sum in one access byte.

bit decimal binary
READ 1 001
WRITE 2 010
REQUIRED 4 100

So, for read/write access one should set access attribute to 3.

1 or 2 => 3

* note that or here is boolean operator

With different types of access we've got more than one access byte of configuration. We call them contexts. Right now we separate 3 context types:

  1. Job sender [S]
  2. Job performer [P]
  3. Beneficiary [B]

In the access attribute we write each access context to it's corresponding decimal place right-to-left B-P-S. E.g. if we've got Sender access set to 3, Performer access set to 7 and Beneficiary access set to 1, then the access should be set to

173

Authentication

To authorize, use this code:

curl "https://www.lastbill.com/api/some" \
-H "Authorization: sometoken"

Make sure to replace sometoken with your API token.

Last Bill uses API tokens to allow access to the API. Once you are a registered user of Last Bill, your personal API token is generated and bound to your account.

We expect your API token to be included in all API requests to the server in a header that looks like the following:

Authorization: sometoken

Account

Login

POST /api/login.json

Login is used to obtain API token.

Request

Replace login and password here.

curl "https://www.lastbill.com/api/login.json" \
-H "Content-Type: application/json" \
-X POST -d '{"user":{"login":"user","password":"pwd"}}'

Request parameters

key value
user hash (required)
User attributes.
user[login] string
Your registered user email or phone number. We don't care about the format of phone number: you can input it as just numbers 375123456789 or formatted +375 (29) 12 - 345-67-89.
user[password] string
Your super secret password "password" or "qwertyui"

Response

Success response

{
  "token": "some-token-here",
  "last_sign_in_at": 1598883752636,
  "last_sign_in_ip": "127.0.0.1",
  "sign_in_count": 135,
  "locale": "en",
  "timezone": "UTC"
}

Failure response

{
  "message": "Invalid Login or Password",
  "error": "invalid_credentials"
}

Success response parameters

key value
token string
Value is the token string.
last_sign_in_at integer (datetime)
Timestamp of last successful login.
last_sign_in_ip string
User IP on last successful login.
sign_in_count integer
Number of times user signed in.

Error responses

http code error code error description
401 invalid_credentials Invalid Login or Password User was not found for given login or password is invalid
403 disabled_account User account is disabled User account was disabled by administrator.
403 no_private_token User has no private token assigned User private token should exist to obtain it. Token is auto-generated when user is created. Administrator should have removed it.

Password forgot

POST /api/password.json

When user lost his password he may request a password reset token. Email or Phone number is required for request. If the email was provided user will receive and email with link, else an SMS message (for phone number).

The link to receive password has the following format: https://<host>/u/p/<reset password token>

E.g. https://lastbill.com/u/p/y7cVLijQYWdB_3KHgDRL.
Here y7cVLijQYWdB_3KHgDRL is a reset password token.

Request

curl "https://www.lastbill.com/api/password.json" \
-X POST -H "Content-Type: application/json" \
-d '{"user": {"login": "1234"}}'

Request parameters

key description
user hash (required)
User attributes.
user[login] string or integer
User email or phone number.

Response

Successful response has no body (status 204 No Content)

Error responses

{
  "error": "not_found",
  "message": "Email or Phone not found"
}

If the user was not found you will receive a 404 (Not Found) error.

Password reset

PUT /api/password.json

Once user have received reset_password_token (see forgot password) it may be used to setup new password.

Request

Make sure to not use such a simple password as provided in the example 😁

curl "https://www.lastbill.com/api/password.json" \
-X PUT -H "Content-Type: application/json" \
-d '{"user": {"reset_password_token": "tokentokentokentoken",\
"password": "password", "password_confirmation": "password"}}'

Request parameters

key description
user hash (required)
User attributes.
user[reset_password_token] string (required)
User reset password token received in the message.
user[password] string (required)
User new password. Minimum length is 6.
user[password_confirmation] string (required)
User password confirmation. Should equal to user[password].

Response

Successful response has no body (status 204 No Content)

Error responses

http code error code description
404 not_found Provided reset password token was not found.
422 unprocessable_entity This may be one of:
  • Token expired.
  • Password did not pass validation.
  • Password confirmation is not equal to password
See error message for details.

Profile

GET /api/profile.json

Read user settings.

Request

Request example.

curl "https://www.lastbill.com/api/profile.json"

Request requires no parameters.

Response

Response example.

{
  "user": {
    "phone": 375291234567,
    "email": "asd@asd.asd",
    "account": {
      "first_name": "asd",
      "last_name": "asd",
      "locale": "en",
      "timezone": "UTC"
    },
    "roles": [
      "admin",
      "performer"
    ]
  },
  "company": {
    "id": "8ada3554-50ab-4154-974d-bbd20c60b1e6",
    "name": "asd",
    "company_logo": {
      "url": "https://www.lastbill.com/assets/logo-lastbill-1130054889e7c14a7631d05268a300b986d46269d81e1278541d5d6b5595ad57.svg",
      "created_at": null
    }
  }
}

Response params

key description
user hash
User attributes container.
user[email] string
User email.
user[unconfirmed_email] string
User email that is gonna replace user[email] after it's confirmation. When user updates email we send a confirmation email to it and until it's confirmed we show new email in user[unconfirmed_email].
user[phone] integer
User phone. See phone format.
user[account] hash
User account attributes container.
user[account][first_name] string
User first name.
user[account][last_name] string
User last name.
user[account][timezone] string
Short timezone name. See TimeZone -> Constants -> Mapping for full timezone names.
user[account][locale] string
Short language code. See locale format
user[roles] array
User roles.
company hash
User company attributes container.
company[id] string
Current company ID.
company[name] string
Current company name.
company[logo] hash
Current company logo attributes container.
company[logo][url] string
Company logo URL.
company[logo][created_at] integer (datetime)
Company logo upload time. If set to null means that company[logo][url] contains reference to default LastBill logo.

Profile update

PUT /api/profile.json

Update user settings.

Request

Request example

curl "https://www.lastbill.com/api/profile.json"
-X PUT -H "Content-Type: application/json" \
-d '{"user": {"phone": "1234", "password": "123", \
"account_attributes": {"first_name": ""}}}'

Request parameters

key description
user hash (required)
User attributes container.
user[email] string
User email.
Can't be blank for admin role.
user[phone] integer
User phone. See phone format.
Can't be blank for performer role.
user[password] string
New user password. Deliver it if you want to change user password.
user[password_confirmation] string
Same as user password.
Can't be blank if user[password] is provided.
user[current_password] string
Current user password.
Can't be blank if user[password] is provided. Must match user[password].
user[account_attributes] hash
User account attributes container.
user[account_attributes][first_name] string
User first name.
user[account_attributes][last_name] string
User last name.
user[account_attributes][timezone] string
Short timezone name. See TimeZone -> Constants -> Mapping for full timezone names.
user[account_attributes][locale] string
Short language code. See locale format
user[device_attributes] hash
User device attributes container.
user[device_attributes][registration_id] string
User device registration id to send push messages.
user[device_attributes][platform] string
User device platform. One of: android, ios.

Response

Failure response

{
  "error": "unprocessable_entity",
  "message": {
    "password": [
      {
        "count": 6,
        "message": "is too short (minimum is 6 characters)",
        "error": "too_short",
        "label": "Password"
      }
    ],
    "phone": [
      {
        "message": "is invalid",
        "error": "invalid",
        "label": "Phone"
      }
    ],
    "current_password": [
      {
        "message": "can't be blank",
        "error": "blank",
        "label": "Current Password"
      }
    ],
    "account": {
      "first_name": [
        {
          "message": "can't be blank",
          "error": "blank",
          "label": "First Name"
        }
      ]
    }
  }
}

Successful response code is 200 OK. Body contains same data as Profile does.

Failure response follows common errors format.

File Upload

Files are uploaded in tree steps:

  1. request url to upload file and signed_id
  2. put the file
  3. submit form with signed_id

POST /api/direct_uploads.json

Request a link to upload file to storage. Server creates temporary link to upload the file based on content type, file size, name and checksum. It returns a url to upload the file and required headers.

Request example

curl "https://www.lastbill.com/api/direct_uploads.json" \
-X POST -H "Content-Type: application/json" \
-d '{"blob": {"filename":"some.txt", "byte_size": 24,\
"checksum": "Zx6e1NXUZEhWexcvGOYvdQ==",\
"content_type":"text/plain"}}'

Compute the checksum

Ruby

Digest::MD5.file('file/path').base64digest

JS

const md5 = CryptoJS.MD5('file content').toString();
Buffer.from(md5, 'hex').toString('base64')

Request parameters

key description
blob hash (required)
Blob attributes.
blob[filename] string (required)
File name of the file being uploaded. Would be used as file label in UI.
blob[byte_size] integer (required)
File size. Should match the uploaded file size. When uploading it, file with other size would be rejected with http code 422.
blob[content_type] string (required)
File MIME type. E.g. text/plain or image/png. When uploading it, file with other content type would be rejected with http code 422.
blob[checksum] string (required)
File checksum calculated MD5 hex encoded with Base64 digest. When uploading it, file with other checksum would be rejected with http code 422.

Response example

{
  "signed_id": "eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaEpJaWxsT1dKaVpXWmtaUz8d93e5a4f6c90f6c7f74b5cd3...",
  "direct_upload": {
    "url": "https://www.lastbill.com/rails/active_storage/disk/eyJfcmFpbHMiOnsibWVzc2FnZSI6IJBaDwer...",
    "headers": {
      "Content-Type": "text/plain"
    }
  }
}

Response parameters

key description
signed_id string
Unique file identifier.
direct_upload hash
Attributes to upload file.
direct_upload[url] string
A URL to put the file.
direct_upload[headers] hash
Collection of required headers to upload the file.

Put file

PUT direct_upload[url]

Once you received a link and signed_id from Request upload link you can upload the file to storage server. Link is expirable, so if you plan to upload multiple files don't request all links at once - only for those you start uploading immediately.

Store signed_id until you successfully submit the form with it. There is no need to re-upload the file if form validation fails: your file already exists in the storage and only signed_id is required.

Submit file reference

When file is uploaded you can submit the form with signed_id in order to attach the file to it's model.

Performer

Location

PUT /api/performer/location.json

Send current performer location.

Request

Request example

curl "https://www.lastbill.com/api/performer/location.json\
?location=1,1" -X PUT

Request parameters

key description
location string (required)
Current performer location. See locations format.

Response

Successful response has no body (status 204 No Content)

Job List

GET /api/performer/jobs.json

Retrieve jobs for performer. Performer is able to fetch jobs that are assigned to it's provider company and not assigned to any performer_user or assigned to current performer.

Request

Request example

curl "https://www.lastbill.com/api/performer/jobs.json"

Request example with list attributes

curl "https://www.lastbill.com/api/performer/jobs.json\
?page=2&order_field=title&filter[query]=asd\
&filter[status][]=in_progress\
&filter[status][]=waiting"

Available filter options

key description
query string
Allows to filter jobs by title or reference.
status array or string
Filter jobs by current job statuses.

Order fields

It is possible to use any job field for order. Default is jobs.created_at desc.

Response

Response example

{
  "meta": {
    "total_pages": 1,
    "total_count": 2,
    "page": 1,
    "per_page": 12,
    "order_field": "id",
    "order_direction": "desc"
  },
  "data": [
    {
      "id": 32,
      "owner_id": 2,
      "owner_name": "Other Corp.",
      "title": "asd",
      "reference": "",
      "own": false,
      "due_date": null,
      "created_at": 1594709429143,
      "updated_at": 1595947043793,
      "status": "assigned",
      "status_name": "Assigned"
    },
    {
        "id": 31,
        "owner_id": 2,
        "owner_name": "Other Corp.",
        "title": "asd",
        "reference": "",
        "own": false,
        "due_date": null,
        "created_at": 1594709409433,
        "updated_at": 1595947043788,
        "status": "assigned",
        "status_name": "Assigned"
    }
  ]
}

Job attributes:

attribute description
id string
Unique job record ID. Use this id to fetch job details using Job Show request.
owner_id string
Job sender (owner) company unique ID.
owner_name string
Job sender name.
title string
Job title.
reference string
Job reference number.
own boolean
Set if performer is assigned to job (performer_user_id = current_user_id).
due_date integer (datetime)
Job due date.
created_at integer (datetime)
Job create at time.
updated_at integer (datetime)
Job last updated at time.
status string
Job status code.
status_name string
Job status translated name.
work_order_address hash
Job's primary address details.
work_order_address[address] string
Primary address.
work_order_address[location] string
Geocoded location for primary address. See locations format.

Job Show

GET /api/performer/jobs/:id.json

Retrieve job details for performer. Performer is able to fetch jobs that are assigned to it's provider company and not assigned to any performer_user or assigned to current performer.

Request

Request example

curl "https://www.lastbill.com/api/performer/jobs/42.json"

Request params:

key value
id string (required)
ID of the job to retrieve.

Response

Response example

{
  "id": 30,
  "title": "asd",
  "reference": "",
  "owner_id": 2,
  "status": "assigned",
  "due_date": null,
  "current_step_uuid": "b069d74e-2f7f-466f-ac67-ce12ac6e1506",
  "performer_user_id": null,
  "created_at": 1594709403315,
  "updated_at": 1595947043781,
  "owner_name": "Other Corp.",
  "status_name": "Assigned",
  "current_step": "Job Summary",
  "workflow": {
    "type": "workflow",
    "uuid": "aa3b7f9d-d23b-4659-982a-6023be440e6f",
    "children": [
      {
        "type": "template_job_info",
        "uuid": "b069d74e-2f7f-466f-ac67-ce12ac6e1506",
        "label": "Job Summary",
        "job_title": "asd",
        "children": [
          {
            "type": "section",
            "uuid": "25fe629d-ea92-4ec4-8e9d-175e502899eb",
            "label": "Section",
            "direction": "col",
            "children": [
              {
                "type": "widget_text",
                "uuid": "0be96ba5-7fb9-4aad-8c1b-7427cc282e1f",
                "label": "First Name",
                "data": "first",
                "data_type": "string",
                "access": 3
              },
              {
                "type": "widget_text",
                "uuid": "2bdefcd7-4e37-4da2-913b-5e1a545cfb98",
                "label": "Last Name",
                "data": "second",
                "data_type": "string",
                "access": 3
              },
              {
                "type": "widget_select",
                "uuid": "ddd51528-719e-4900-a8d9-69feddc6ee87",
                "label": "Select Multiple",
                "data": [
                  "option 1"
                ],
                "data_type": "checkbox",
                "access": 3,
                "options_list": [
                  "option 1",
                  "option 2"
                ],
                "multiple": true
              }
            ]
          }
        ]
      },
      {
        "type": "template_blank",
        "uuid": "56987c0d-a265-4900-aca0-482b61298e29",
        "label": "Blank",
        "children": [
          {
            "type": "section",
            "uuid": "a5bf9c4d-40b8-427d-af49-ab8ea11cc354",
            "label": "",
            "direction": "col",
            "children": [
              {
                "type": "widget_text",
                "uuid": "8762269f-eff1-47a8-92cb-119956bac4f5",
                "label": "Label",
                "data": "asd",
                "data_type": "string"
              }
            ]
          }
        ]
      },
      {
        "type": "template_navigation",
        "uuid": "df2f25b2-6dd8-40fc-9487-900cc000ab4c",
        "label": "Navigation",
        "performer_notifications": true
      }
    ]
  }
}

Response attributes:

key description
current_step_uuid string
UUID of the current not completed Job's template. Only step with UUID current_step_uuid and previous steps are allowed to be updated.
current_step string
Label of the current not completed Job's template.
workflow hash
Workflow structure with data. Attributes of the workflow are explained in Job Workflow section.

Rest attributes description see in job list endpoint.

Job Template Update

PUT /api/performer/jobs/:job_id/templates/:id.json

Update job template with data. This step requires workflow cell's UUIDs. They are available through the Show Job endpoint. All data is wrapped with data hash.

Template is allowed to be updated if it is already completed or is a current step of the job. See Show Job response attributes for current_step_uuid.

Say, we have template blank with a section with two widgets: {"type":"widget_text", "data_type": "phone", "uuid": "phone1", "label": "Phone Number"} and {"type":"widget_text", "data_type": "string", "uuid": "name1", "label": "Full Name"}.
The update data for those widgets should look {"data": {"phone1": 123123123, "name1": "Jim Beam"}}

Request

Request example

curl "https://www.lastbill.com/api/performer/jobs/32/\
templates/b069d74e-2f7f-466f-ac67-ce12ac6e1506.json" \
-X PUT -H "Content-Type: application/json" \
-d '{"data":{"0be96ba5-7fb9-4aad-8c1b-7427cc282e1f": ""},\
"submitted_at":1600475328942, "location":"53.6995213,23.7728246"}'

Request parameters

key description
job_id string (required)
ID of the job to update.
id string (required)
UUID of the template to update.
submitted_at integer (datetime)
Data submission time from performer.
location string
Data submission location from performer. See locations format.
data hash
Data collection for template attributes and widgets.

Response

Successful response has no body (status 204 No Content)

Failure response example

{
  "0be96ba5-7fb9-4aad-8c1b-7427cc282e1f": [
    "Data can't be blank"
  ]
}

Failure response would have status 422(Unprocessable Entity). Failure response would be a hash where keys are widget UUID's and values follow the Error format.

Job Template Custom Update

PUT /api/performer/jobs/:job_id/templates/:template_id/:data_method.json

With this generic scheme we expect any custom data updates to templates. These updates add data to template, but don't complete the step of the job. E.g. performer will send location points of his route when driving to destination point of navigation template.

Request

Request example

curl "https://www.lastbill.com/api/performer/jobs/32/\
templates/b069d74e-2f7f-466f-ac67-ce12ac6e1506/\
performer_location.json" \
-X PUT -H "Content-Type: application/json" \
-d '{"data":{"submitted_at":1600475328942,\
"location":"53.6995213,23.7728246"}}'

Request parameters

key description
job_id string (required)
ID of the job to update.
template_id string (required)
UUID of the template to update.
data_method string (required)
Custom method to execute in template.
data anything (required)
Data for template. See details in the next section - Custom Requests

Response

Successful response has no body (status 204 No Content)

Failure response example

{
  "template": [
    "Data can't be blank"
  ]
}

Custom Requests

In this section we explain what data is expected by templates in their custom update methods.

Template Navigation

Performer location data example

{
  "data": {
    "location": "1,1",
    "submitted_at": 1602023711000
  }
}
  1. performer_location
key description
data hash (required)
data[submitted_at] integer (datetime)
Time of data submission. May be stored for cases when performer has no internet and sent when online.
If not provided we set current (request processing) timestamp.
data[location] string (required)
Performer location at submitted_at time. See locations format.

Batch location example

{
  "data": [
    { "location": "1,1" },
    { "location": "2,1", "submitted_at": 1602023711000 },
    ...
  ]
}

It is also possible to send batch of locations. Then data format should be an array of hashes.

Companies

List

GET /api/companies.json

List of companies, except current_company user belongs to.

Request

Request example

curl "https://www.lastbill.com/api/companies.json\
?page=2&per_page=50"

Available filter options

key description
query string
Allows to filter companies by name and reference.
categories array or string
Lookup codes of categories company should have.
This filter works as ANY, meaning that if company has at least one of provided categories it would appear in the result list.
locations array or string
Countries and cities company should be from.
Format is **country_code
certified boolean
Include only certified companies.

Order fields

It is possible to use any company field for order. Default is companies.name asc.

Response

Response example

{
  "meta": {
    "total_pages": 1,
    "total_count": 2,
    "page": 1,
    "per_page": 12,
    "order_field": "name",
    "order_direction": "asc"
  },
  "data": [
    {
      "id": "a806c5c9-d749-4947-8194-778df504971c",
      "name": "Not Linked Corp.",
      "registration_number": "not_linked",
      "country_code": "by",
      "country_name": "Belarus",
      "city": null,
      "config": {
        "short_description": "not linked test company",
        "company_logo": {
          "url": "https://www.lastbill.com/packs/media/images/logo-lastbill-b40dcd30cdb84bbc59f79f73362991a3.svg",
          "created_at": null
        }
      }
    },
    {
      "id": "93681c24-0d8d-4f91-91e5-dd7d6e32a803",
      "name": "Other Corp.",
      "registration_number": "other",
      "country_code": "by",
      "country_name": "Belarus",
      "city": null,
      "config": {
        "short_description": "other test company",
        "company_logo": {
          "url": "https://www.lastbill.com/packs/media/images/logo-lastbill-b40dcd30cdb84bbc59f79f73362991a3.svg",
          "created_at": null
        }
      }
    }
  ]
}

Company attributes

attribute description
id string
Unique company ID. Use this id to fetch company details using Company Show request.
name string
Company name.
registration_number string
Company home-country registration number (it may be a unique tax payer number).
country_code string
Company's country code from ISO3166 standard.
country_name string
Translated country name.
city string
Company's city.
config hash
Company's additional configuration.
config[short_description] string
Brief company description.
config[company_logo] hash
Card logo attribues.
config[company_logo][url] string
URL to download the logo.
config[company_logo][created_at] integer (datetime)
Timestamp when the logo was uploaded.

Show

GET /api/companies/:id.json

Company detailed attributes.

Request

Request example

curl "https://www.lastbill.com/api/companies/ae6489f7-10a6-48ce-8b6c-73377ebf3f3a.json"

Request parameters

key description
id string (required)
Unique ID of the company.

Response

Response example

{
  "id": "ae6489f7-10a6-48ce-8b6c-73377ebf3f3a",
  "name": "Main Corp.",
  "registration_number": "main",
  "country_code": "fr",
  "country_name": "France",
  "city": "",
  "config": {
    "short_description": "test company",
    "website_url": "",
    "linkedin_url": "",
    "facebook_url": "",
    "twitter_url": "",
    "instagram_url": "",
    "company_logo": {
      "url": "https://www.lastbill.com/rails/active_storage/representations/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaEpJaWxoWWpkbU1tRmtZUzAzWlRFM0xUUmhaVEV0WWpWbU15MDFNR1U1WXpOa05qQTROR1FHT2daRlZBPT0iLCJleHAiOm51bGwsInB1ciI6ImJsb2JfaWQifX0=--558183a78ffc2a4a16495931630b7c7e82f1f469/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCam9VY21WemFYcGxYM1J2WDJ4cGJXbDBXd2RwQVpacEFaWT0iLCJleHAiOm51bGwsInB1ciI6InZhcmlhdGlvbiJ9fQ==--ab3b5c46864b6528c9614abc09ae0f709ab5b827/Screenshot%20from%202020-07-12%2000-06-37.png",
      "created_at": 1603446033706
    },
    "description": "<div>test company for developers</div>"
  }
}

Response parameters (in addition to list of companies).

key description
description Company description.
config[*_url] Links to websites and social networks, associated with company.

Jobs

List

GET /api/jobs.json

List of company's jobs.

TBD;

Show

GET /api/jobs/:id.json

Details of the job.

TBD;

Send with JSON

POST /api/jobs.json

Send job with JSON workflow and data within. This endpoint allows to send job with one request.

Request

Request example

curl "https://www.lastbill.com/api/jobs.json" \
-X POST -H "Content-Type: application/json" \
-d '{"target_id": "ae6489f7-10a6-48ce-8b6c-73377ebf3f3a",\
"workflow": {"children": [{"type": "template_job_info",\
"job_title":"title","job_due_date":1603749261000,\
"job_address": "addr 1", "job_location": "1,1"}],\
"type": "workflow"}}'

Request parameters

key description
draft boolean
Set to true if you plan to modify job later, instead of sending. The job would be marked "draft" and won't be available to partner.
target_id string
UUID if partner you want to assign a job.
workflow hash (required)
Workflow structure with data. See workflows section.

Response

Successful response

{"id": "e517cf56-7e16-4e17-b7e4-14842f5f7ff2"}

Successful response code is 200 OK. Response data contains an id of newly created job.

Failure response

{
  "error": "validation_error",
  "message": {
    "tji1": {
      "job_due_date": [
        "Due Date can't be blank"
      ]
    }
  },
  "invalid_workflow": {
    "type": "workflow",
    "uuid": "wf1",
    "children": [
      {
        "type": "template_job_info",
        "uuid": "tji1",
        "label": "Job Summary",
        "completed": true,
        "job_title": "Sample Workflow",
        "job_address": "addr 1",
        "job_location": "1,1"
      },
      {
        "type": "template_blank",
        "uuid": "tb1",
        "label": "Client Info",
        "completed": true,
        "children": [
          {
            "type": "section",
            "uuid": "s1",
            "label": "Client Name",
            "direction": "col",
            "children": [
              {
                "type": "widget_text",
                "uuid": "first_name",
                "label": "First Name",
                "data_type": "string",
                "reference": "first_name",
                "access": 1
              },
              {
                "type": "widget_text",
                "uuid": "ln1",
                "label": "Last Name",
                "data_type": "string",
                "data": "Beam",
                "access": 1
              },
              {
                "type": "widget_text",
                "uuid": "phone1",
                "label": "Phone",
                "data_type": "phone",
                "data": 555123
              },
              {
                "type": "widget_text",
                "uuid": "addr1",
                "label": "Address",
                "data_type": "string",
                "reference": "address"
              }
            ]
          }
        ]
      },
      {
        "type": "template_navigation",
        "uuid": "nav",
        "label": "Nav Label",
        "completed": true,
        "address": "addr 2",
        "location": "2,2"
      }
    ]
  }
}

When workflow or job attributes don't meet the requirements 422 Unprocessable Entity is returned. Error message contains detailed explanation of what went wrong. Also we add invalid_workflow to the response, to show how the workflow looked when errors occurred.

Job Workflows

List

GET /api/job_workflows.json

List of company's job workflows.

Request

Request example

curl "https://www.lastbill.com/api/job_workflows.json"

Available filter options

key description
query string
Allows to filter job workflows by title.

Order fields

It is possible to use any job workflow's field for order. Default is job_workflows.title asc.

Response

Response example

{
  "meta": {
    "total_pages": 1,
    "total_count": 1,
    "page": 1,
    "per_page": 100,
    "order_field": "title",
    "order_direction": "asc"
  },
  "data": [
    {
      "id": "8c743786-bdb4-457b-a22a-639f72b08fd4",
      "title": "asd",
      "icon": "icon-1",
      "draft": false
    }
  ]
}

Parameters are explained below in show endpoint.

Show

GET /api/job_workflows/:id.json

Details of the job workflow.

Request

Request example

curl "https://www.lastbill.com/api/job_workflows/\
8c743786-bdb4-457b-a22a-639f72b08fd4.json"

Request params

key description
id string (required)
Unique ID of the job workflow.

Response

Response example

{
  "id": "8c743786-bdb4-457b-a22a-639f72b08fd4",
  "title": "asd",
  "icon": "icon-1",
  "draft": false,
  "workflow": {
    "type": "workflow",
    "uuid": "f76388ba-eb6b-465d-a39a-5b49d2324007",
    "children": [
      {
        "type": "template_job_info",
        "uuid": "74fbbe64-4a1b-4f57-9b3d-f774c3629e5b",
        "label": "Job Summary"
      }
    ]
  },
  "created_at": 1602834840789,
  "updated_at": 1602834856128
}

Response parameters

key description
id string
Unique ID of the job workflow.
title string
Title of the job workflow.
icon string
Icon for job workflow in the web UI.
draft boolean
Job workflows marked draft can't be used to send job.
workflow hash
Workflow structure. See workflows.
created_at integer (datetime)
Creation time.
updated_at integer (datetime)
Last update time.

Send Job

POST /api/job_workflows/:id/send_job.json

Send job with job workflow reference and data with one request.

Request example

curl --location --request POST \
'https://www.lastbill.com/api/job_workflows/\
8c743786-bdb4-457b-a22a-639f72b08fd4/send_job.json' \
--header 'Content-Type: application/json' \
--data-raw '{
  "data": {
    "74fbbe64-4a1b-4f57-9b3d-f774c3629e5b": {
      "job_title": "test title",
      "job_due_date": 1602834840789,
      "job_address": "addr 1",
      "job_location": "1,1"
    }
  }
}'

Request parameters

key | description id | string (required)
Unique ID of the job_workflow. draft | boolean
Set to true if you plan to modify job later, instead of sending. The job would be marked "draft" and won't be available to partner. data | hash (required)
Data for templates. data[template-uuid] | hash
Data for template with UUID template-uuid.

E.g. for template Job Info with id job_info_1234 the data should be passed:

{ "data": { "job_info_1234": { <HERE> } }}

Response

Successful response

{"id": "e517cf56-7e16-4e17-b7e4-14842f5f7ff2"}

Successful response code is 200 OK. Response data contains an id of newly created job.

Failure response

{
  "error": "validation_error",
  "message": {
    "74fbbe64-4a1b-4f57-9b3d-f774c3629e5b": {
      "job_due_date": [
        "Due Date can't be blank"
      ]
    }
  }
}

When workflow or job attributes don't meet the requirements 422 Unprocessable Entity is returned. Error message contains detailed explanation of what went wrong.