Introduction

Hello Developers

Welcome to the Handy integration guide!

(If you aren't a developer or you have no idea what an "API" is and you just want to sign in to your Handy account, you can do that here.)

In this guide, we'll take you to through the process of using the Handy API to integrate it with your main system or ERP.

The Handy API is REST based, uses the JSON data format and is secured with HTTPS. You can use it to build an application to interact with your ERP or other systems.

If you need support, please use the chat right here on the bottom right corner to ask questions.

Quick Start

Here is the quick and dirty way to get started:

  1. Create a free account on Handy. You don't need a credit card. You'll get the full product for 14 days. In case you need more time, just let us know on the chat.
  2. Create an API token. Go edit your user and press the green button to create your personal API token.
  3. Test your token. Open a terminal window and run this:
    curl -H "Authorization: Bearer API_TOKEN" https://app.handy.la/api/v2/user

You should get a response that looks something like this:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "pagination": {
        "totalCount": 50,
        "totalPages": 5,
        "currentPage": "https://app.handy.la/api/v2/user?page=1",
        "nextPage": "https://app.handy.la/api/v2/user?page=2",
        "prevPage": null,
        "firstPage": "https://app.handy.la/api/v2/user?page=1",
        "lastPage": "https://app.handy.la/api/v2/user?page=5"
    },
    "users": [
        {
            "id": 1153,
            "username": "enrique@gmail.com",
            ...
        }
    ]
}

                

That's it! You just received a list of your users in JSON format through the Handy API 🥳.

These are some other important technical considerations regarding the API that you will find under the full API spec:

  1. There are rate limits that you must take into account, specially if you do parallel calls. The limit is relatively high, so you'll only incurr it if there is an abuse pattern.
  2. Use the dd/MM/yyyy HH:mm:ss format for dates. Don't forget to encode it if it's a URL query param.
  3. Reading results are paginated. You are on the last page when nextPage is null.
  4. API calls have a timeout of 30 seconds.

You can get the full API reference here, but for now, let's understand the common use cases in order to create something more substantial.

Use cases

Overview

Since Handy is a Sales Force Automation (SFA) system, optimized for work 🚚 on field, the most common integration pattern is taking master data from your central system, having sales persons capture sales orders on field and then syncing those orders back to your main system.

This way you can do credit check, invoicing, picking, delivery, etc. on your main system.

It works like this:

flow diagram

Where your system can be an ERP like Odoo, SAP Business One or any other ERP.

Sales

We will fist explain how to sync your sales from Handy to your main ERP. Althought not required for syncing sales, we'll first explain you how to sync your master data in order to be used on Handy.


Taking data from your system (customers, products, etc.) to Handy

Althought you can mass-import customer, product and pricing data to Handy, it's convenient to have it all synchronized automatically.

For this, you need to create a cron job or Windows scheduled task to sync deltas every 10 minutes or so. Here is an example for customers:

  1. First do a customer mass-import using the Excel template.
  2. Set a recurring task querying your ERP database for changes in the last 10 minutes.
  3. POST new customers and PUT the changes to Handy, using the https://app.handy.la/api/v2/customer endpoint.
  4. You need to do it one customer at a time.
  5. Handy will automatically distribute the corresponding data to the sales persons mobile app. You only need to communicate with the API.

This same pattern can be repeated for products and price lists using these endpoints:

  1. Products: https://app.handy.la/api/v2/product
  2. Price list: https://app.handy.la/api/v2/priceList

🏬 Mapping customer fields

Creating a customer on Handy only has three required fields: code, description and zone. It's a good practice to use your ERP's customer code or ID as the customer code in Handy. The code is an assigned String on Handy. That way, you'll be able to map customers on both systems.

The description field is open, you can use the customer name or tax ID.

The zone field is a very important one because it's the field used to match sales reps with customers. A good practice is to user the assigned sales rep on the ERP as the zone description. That way, you'll match assigned customers on your ERP with assigned customers on Handy.

🛍 Mapping product fields

Products have four required fields: code, description, product familiy and price .

The first three fields are pretty straightforward: you can use the code for the product ID on your main system, the description is the name of the product and the product family is the group of products to which it belongs.

The price stablished in this field is the regular price for all customers. In case you need to use a specific price list for a certain group of customers, take a look at the next section abour price lists.

🏷 Mapping price list fields

In Handy, you can create multiple price lists and assign them to customers. Each customer, can have only one price list assigned at a time.

The first step to use price lists is creating the parent record, that is the price list identifier and name. You can do that on the web UI or using the API.

Once you do that, you can PUT to the https://app.handy.la/api/va/priceList/PRICE_LIST_CODE endpoint to add items like this:

{
    "items": [
        {"product": "P001", "price": 56.3},
        {"product": "P002", "price": 21.0}
    ]
}

You can add as many items as you want to this request, but we recommend doing it in batches of around 100 items.


Taking data from Handy (sales) to your system

In the opposite direction, you can take data from Handy to your system by polling the API.

You can poll for new sales orders by performing a GET request to the https://app.handy.la/api/v2/salesOrder endpoint.

The recommendation is to do it each 10 minutes or so. You can achieve that by using the start and end query parameters, like this:

curl -H 'Authorization: Bearer API_TOKEN' 'https://app.handy.la/api/v2/salesOrder?start=01/05/2020%2012:00:00&end=01/05/2020%2013:00:00'

Remember to URL encode the query parameters, and you'll get a result like this one:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "pagination": {
        "totalCount": 6,
        "totalPages": 1,
        "currentPage": "https://app.handy.la/api/v2/salesOrder?page=1",
        "nextPage": null,
        "prevPage": null,
        "firstPage": "https://app.handy.la/api/v2/salesOrder?page=1",
        "lastPage": "https://app.handy.la/api/v2/salesOrder?page=1"
    },
    "salesOrders": [
        {
        "id": 7391919,
        "mobileDateCreated": "2020-05-01T17:43:04Z",
        "customer": {
            "code": "A4",
            "zone": {
                "description": "Guadalajara",
                "id": 980,
                "enabled": true
            },
            "description": "Stark Industries",
            "id": 4,
            "enabled": false
        },
        "createdBy": {
            "name": "Bernardo Bravo",
            "id": 622,
            "enabled": true,
            "username": "user@gmail.com"
        },
        "items": [
            {
            "isReturn": false,
            "product": {
                "code": "ACME-02-006",
                "quantity": 1.5,
                "satUnitCode": "",
                "description": "Monociclo Propulsado Acme",
                "satProductCode": "",
                "enabled": true,
                "price": 1500.123456,
                "hasBeenSold": false,
                "details": null,
                "applyDiscounts": true,
                "id": 2032143,
                "family": {
                    "description": "Mecánicos",
                    "id": 45033,
                    "enabled": true
                },
                "category": null,
                "barcode": null,
                "taxType": 0
            },
            "total": 10500.864192,
            "quantity": 7.0,
            "comments": null,
            "originalPrice": 0.0,
            "isReward": false,
            "price": 1500.123456,
            "discount": null,
            "id": 25223135,
            "promoIds": null,
            "promoNames": null
            },
        ],
        "type": {
            "description": "Cambio físico",
            "id": 12028,
            "enabled": true
        },
        "exported": false,
        "deleted": false,
        "sellerComment": null,
        "scheduledDateForDelivery": "2020-05-02T17:43:04Z",
        "latitude": 20.646848911292956,
        "longitude": -103.45223890705688,
        "accuracy": 0.0,
        "tookInPlace": true,
        "priceList": null,
        "totalSales": 11700.864192,
        "billable": false,
        "billed": false,
        "routeSalePaymentType": null,
        "dateCreated": "2020-05-02T02:00:10Z",
        "promoIds": null,
        "promoNames": null,
        "networkSignalQuality": -1,
        "creationSource": "MOBILE",
        "dateDeleted": null,
        "deletedBy": null,
        "editedFrom": null,
        "isEdited": false
        },
    ]
}
            

As you can see, we polled for a 10 minute time period. Once you do that, you typically save the datetime used and poll again for the next 10 minutes.

What if I have returns?. On each item, you'll see the isReturn field. In both cases, the quantity field is going to be a positive number but you can identify returns with the boolean isReturn field. The total field on each item (money amount) will do have a sign, it's negative for returns.

That you have the sales recorded on your main system, you can proceed with invoicing, pickup and delivery 🚚 🥳 .


Deliveries

When using Handy to track customer deliveries, additionally to the provided reports on Handy, you can query the delivery endpoints in order to sync back the data to your main systems and proceed with further processes such as generating a credit note on incomplete deliveries.

It is common to accompany the delivery process with a customer invoice. In case the delivery is not fulfilled in its entirety, you may want to know this information, additionally to understanding when a delivery was fully delivered.

Here is how to do that:

  1. Run a job at the time all delivery routes are finished, it can be a nightly job, let's say 11:00 PM.
  2. Query the user's list with https://app.handy.la/api/v2/user
  3. and for each user with userType.code == 'DELIVERY', do the following.
  4. Query the user's deliveries with https://app.handy.la/api/v2/user/{userId}/deliveries by passing the start and end date parameters set for today at start of day and today at end of day.
  5. Now you can analyze each delivery and its result. Here is an example of how it looks for 1 user, with 1 delivery attempt:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "pagination": {
        "totalCount": 1,
        "totalPages": 1,
        "currentPage": "https://app.handy.la/api/v2/user/2/deliveries?start=18/09/2020 00:00:00&end=18/09/2020 23:59:59&page=1",
        "nextPage": null,
        "prevPage": null,
        "firstPage": "https://app.handy.la/api/v2/user/2/deliveries?start=18/09/2020 00:00:00&end=18/09/2020 23:59:59&page=1",
        "lastPage": "https://app.handy.la/api/v2/user/2/deliveries?start=18/09/2020 00:00:00&end=18/09/2020 23:59:59&page=1"
    },
    "deliveries": [
        {
            "id": 6649605,
            "code": "5367457",
            "scheduledDate": "2020-09-18T06:47:00Z",
            "deliveredDate": "2020-09-18T16:11:00Z",
            "deliveredInPlace": true,
            "comments": "",
            "customer": {
                "code": "5309",
                "zone": {
                    "description": "Guadalajara",
                    "id": 980,
                    "enabled": true
                },
                "description": "Oscorp",
                "id": 5309,
                "enabled": true
            },
            "salesOrders": [
                {
                    "id": 5367457,
                    "items": [
                        {
                            "productCode": "ACME-03-008",
                            "quantity": 19.0,
                            "delivered": 5.0,
                            "salesOrderItemId": 17849893,
                            "quantityToAssign": 14.0
                        }
                    ]
                }
            ],
            "route": {
                "comments": null,
                "dateCreated": "2020-09-18T16:10:09Z",
                "finishedByUser": false,
                "createdBy": {
                    "code": "SALES",
                    "description": "Preventa",
                    "id": 1,
                    "class": "com.locus.user.UserType"
                },
                "initialAmount": 0.0,
                "dateFinishedByUser": null,
                "closed": false,
                "id": 247,
                "dateClosed": null,
                "user": "arturo+android@handy.la",
                "status": "onRoute"
            },
            "items": [
                {
                    "id": 13326426,
                    "code": "ACME-03-008",
                    "description": "Rocas deshidratadas Acme",
                    "quantity": 19.00,
                    "productId": 2032144,
                    "price": 646.00,
                    "deliveredQuantity": 5.00,
                    "delivered": false,
                    "notDeliveredReason": "producto dañado",
                    "salesOrderItems": [
                        {
                            "id": 17849893,
                            "salesOrderId": 5367457,
                            "totalQuantity": 19.0000,
                            "assignedQuantity": 19.00,
                            "price": 34.000000,
                            "isPromo": false,
                            "promoIds": "",
                            "withDiscount": false,
                            "quantityDiscount": 0,
                            "percentageDiscount": 0,
                            "code": "ACME-03-008",
                            "familyId": 45033,
                            "familyName": "Mecánicos"
                        }
                    ]
                }
            ],
            "result": {
                "id": 2,
                "description": "Entregado tarde",
                "effective": true
            }
        }
    ]
}

            

You will see that you have a deliveries array. Each delivery, represents a visit to one customer.

For each delivery, you have the items (products), and for each one, you can see if it was a complete delivery by checking the quantity (assigned) and deliveredQuantity, and also the notDeliveredReason.


Inventory

We will be adding details on how to connect your warehouse inventory in real time. In the meantime you can check this article.


Outside customer data

We will be adding details on how to fetch and display customized information about your customers. In the meantime you can check this article.


Outside sales orders

Handy is optimized to use sales orders captured on the Handy apps for delivery purposes. However, it's possible to integrate sales orders created from external systems like an ERP or an e-commerce site in order to perform deliveries using Handy.

Here is how to do that:

  1. Make sure you have created/sync'd your customers on Handy. See the sales sync process for more information on this.
  2. Use the https://app.handy.la/api/v2/salesOrder endpoint to POST each new sales order from your system.

That way, you can now process and assign sales orders to delivery users. You can learn more about those processes in the Handy Academy under this section .

You only need to specify the sales order customer and products. Handy will be able to map which users must perform each corresponding delivery when you assign the deliveries on the webapp.

FAQ

Do you have SDKs?
Not yet, but we have plans to develop them for C# and Java, since they are the main Enterprise programming languages. We don't have estimated release dates for them.

Do you support webhooks instead of polling?
Not yet, but we have plans to develop them. We don't have estimated release dates for them.

Still have questions? Schedule a technical meeting with us below 👇🏻: