Welcome to the Hotbox Technology API Documentation. This guide provides information on accessing and utilizing various Hotbox Technologies Azapay's API services for business.

Getting Started

Before using the Terminal Request Service API, ensure you have: These credentials are important for authenticating your requests and should be passed as request headers in the following format: Api-Key and Business-Id. We currently have the following services.
  1. Terminal Service
  2. Payment Service
  3. Wallet Service
Each service is documented and can be accessed by clicking on the service folder whenever you want to integrate. However, they all share the same unique filtering system.

API URL(s)

The testing and production URL(s) can be found for each service documentation.

Understanding How Filter Data

This API provides a very flexible way to filter data. This filter applies to endpoint(s) that allow it and the API documentation for each endpoint(s) will specify its application status. Here is a sample JSON with randomly generated data.
// USERS
[{
  "id": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
  "firstName": "Dulcy",
  "lastName": "Strond",
  "email": "dstrond0@ted.com",
  "profile": {
  "id": "a6a92909-af16-4bc6-953b-e1784bed5ce8",
    "userId": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
    "age": 25,
    "dateOfBirth": "8/23/2023"
  },
  "address": [{
    "id": "f06c78c9-79bc-45b3-97a8-d906f66a6a9a",
    "userId": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
    "address": "PO Box 78148"
  }, {
    "id": "56dc1eaa-d192-4c7d-acc3-83f0cfc98f1b",
    "userId": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
    "address": "Room 974"
  }],
  "phoneNumber": [{
    "id": "5c1ed059-7928-4d4d-ac7f-1ab5efd2c108",
    "userId": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
    "phone_number": "773-374-4168"
  }, {
    "id": "0094e11a-3e6f-4255-9bb8-3b1a4ddc34e7",
    "userId": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
    "phone_number": "826-613-4213"
  }]
}, {
  "id": "03ec9a58-7325-42e9-8de6-01876fac35e1",
  "firstName": "Alene",
  "lastName": "Pyecroft",
  "email": "apyecroft1@prnewswire.com",
  "profile": {
    "id": "d9911cf0-6281-4c0d-a082-c725e202206b",
    "userId": "03ec9a58-7325-42e9-8de6-01876fac35e1",
    "age": 40,
    "dateOfBirth": "7/27/2023"
  },
  "address": [{
    "id": "63b2e723-22c0-4a82-a8d6-69980d9b3b3d",
    "userId": "03ec9a58-7325-42e9-8de6-01876fac35e1",
    "address": "Room 81"
  }],
  "phoneNumber": []
}, {
  "id": "009c3b6b-e0d6-4967-aa5c-64be94b50f54",
  "firstName": "Mildrid",
  "lastName": "Figin",
  "email": "mfigin2@creativecommons.org",
  "profile": {
    "id": "20b5d742-8816-47bc-a608-0e5daf0292f5",
    "userId": "ef0f954c-5bf9-43ed-b043-1d0c1fe437fb",
    "age": 32,
    "dateOfBirth": "5/29/2023"
  },
  "address": [],
  "phoneNumber": [{
     "id": "3f0895f4-2523-48c5-88e8-2dae72c79111",
     "userId": "009c3b6b-e0d6-4967-aa5c-64be94b50f54",
     "phone_number": "614-836-9746"
   }]
}, {
  "id": "d6885c37-779e-4a1c-b3a9-82bedd7e1981",
  "firstName": "Noble",
  "lastName": "Gillum",
  "email": "ngillum3@posterous.com",
  "profile": {
    "id": "c7070f67-5b87-4583-ad36-577074618d50",
    "userId": "d6885c37-779e-4a1c-b3a9-82bedd7e1981",
    "age": 23,
    "dateOfBirth": "4/21/2024"
  },
  "address": [{
    "id": "6f003e4e-f5ce-430b-824a-be1eab8fb230",
    "userId": "d6885c37-779e-4a1c-b3a9-82bedd7e1981",
    "address": "Room 1182"
    }, {
    "id": "6452ce2b-938e-4016-93fc-2704acc64541",
    "userId": "d6885c37-779e-4a1c-b3a9-82bedd7e1981",
    "address": "PO Box 55577"
  }],
  "phoneNumber": [{
    "id": "600793bc-9014-4cc3-89ce-e0225e072fce",
    "userId": "d6885c37-779e-4a1c-b3a9-82bedd7e1981",
    "phone_number": "176-529-5473"
   }]
}, {
  "id": "6a119cca-4f92-4a52-8e86-2d26b5389668",
  "firstName": "Aeriel",
  "lastName": "Trittam",
  "email": "atrittam4@jigsy.com",
  "profile": {
    "id": "a4f46f1f-3083-419b-97fd-7177181482ed",
    "userId": "6a119cca-4f92-4a52-8e86-2d26b5389668",
    "age": 21,
    "dateOfBirth": "10/7/2023"
  },
  "address": [],
  "phoneNumber": [{
    "id": "4a44c978-dbaf-405f-bae7-e6ffee6f0be9",
    "userId": "6a119cca-4f92-4a52-8e86-2d26b5389668",
    "phone_number": "748-428-6101"
  }]
}]

Here is the structure of a sample filter JSON
{
  "filter":"true",
  "more":"true",
  "pageNumber": 1,
  "batchNumber": 10,
  "sort": "ASC",
  "orderBy" :"firsName",
  "groups": [{
    "filterGroupCondition":"AND",
      "filters": [{
          "searchCondition": "AND",
          "filterOption": "cn",
          "field": "firstName",
          "value": "foma",
          "dataType": "string"
       }]
    }]
}

Filter: This can be set to either true or false, when it is set to true, you can set groups to an empty array eg
{
  "filter":"false",
  ....
  "groups": []
}

More: This can be set to either true or false, when it is set to true, you can get all data if false so data may be omitted eg
// FILTER
{
  "more":"false",
  ....
}
// RESPONSE
[{
  "id": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
  "firstName": "Dulcy",
  "lastName": "Strond",
  "email": "dstrond0@ted.com",
}, {
  "id": "6a119cca-4f92-4a52-8e86-2d26b5389668",
  "firstName": "Aeriel",
  "lastName": "Trittam",
  "email": "atrittam4@jigsy.com"
}]

NOTE: The above response is missing user.profile, user.address, and user.phoneNumber
// FILTER
{
  "more":"true",
  ....
}
// RESPONSE
[{
  "id": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
  "firstName": "Dulcy",
  "lastName": "Strond",
  "profile": {
  "id": "a6a92909-af16-4bc6-953b-e1784bed5ce8",
    "userId": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
    "age": 25,
    "dateOfBirth": "8/23/2023"
  },
  "address": [{
    "id": "f06c78c9-79bc-45b3-97a8-d906f66a6a9a",
    "userId": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
    "address": "PO Box 78148"
  }, {
    "id": "56dc1eaa-d192-4c7d-acc3-83f0cfc98f1b",
    "userId": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
    "address": "Room 974"
  }],
  "phoneNumber": [{
    "id": "5c1ed059-7928-4d4d-ac7f-1ab5efd2c108",
    "userId": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
    "phone_number": "773-374-4168"
  }, {
    "id": "0094e11a-3e6f-4255-9bb8-3b1a4ddc34e7",
    "userId": "1c379a27-7cb1-4878-809e-ffa4857f4fa0",
    "phone_number": "826-613-4213"
  }]
}]

NOTE: when set as true, it returns both the user-data and user-related data. Page Number: it's used for pagination and its starting value is 1. Batch Number: It determines the number of records to return per page. Sort: it determines the arrangement of the returned records in ascending or descending order. Expected values are ASC | DESC Order By: It determines the field the sort (above) will be applied to. Also, a URL will be provided to inform you of the expected value for this field eg GET("baseUrl/allowed-query/fields/users") Groups: This is used to group multiple search conditions into AND & OR
{
  ...
  "groups": [{
    "filterGroupCondition":"AND",
    "fieldSearchCondition": "OR",
    "filters": [{
        "filterOption": "cn",
        "field": "firstName",
        "value": "foma",
        "dataType": "string"
     }, {
        "filterOption": "cn",
        "field": "lastName",
        "value": "foma",
        "dataType": "string"
     }]
   }, {
    "filterGroupCondition":"OR",
    "fieldSearchCondition": "OR",
    "filters": [{
        "filterOption": "gt",
        "field": "age",
        "value": "4",
        "dataType": "number"
     }, {
        "filterOption": "cn",
        "field": "email",
        "value": "foma",
        "dataType": "string"
     }]
  }]
}

From the above, These are the steps that will run to produce the result
  1. Group 1
    1. find data where
Filters: You can look at the filter as an if, else conditional statement with each object is a single condition. eg following the above JSON sample FilterOption: These are the conditions that determine the filtering logic. You can visit GET("baseUrl/search-condition") to see all the search conditions. These are currently the allowed search conditions
{
  "data": [
    {
      "condition": "ncn",
      "meaning": "does not contain"
    },
    {
      "condition": "new",
      "meaning": "does not end with"
    },
    {
      "condition": "nsw",
      "meaning": "does not start with"
    },
    {
      "condition": "cn",
      "meaning": "contain"
    },
    {
      "condition": "sw",
      "meaning": "start with"
    },
    {
      "condition": "ew",
      "meaning": "end with"
    },
    {
      "condition": "gt",
      "meaning": "greater then"
    },
    {
      "condition": "gte",
      "meaning": "greater then or equals to"
    },
    {
      "condition": "lt",
      "meaning": "less then"
    },
    {
      "condition": "lte",
      "meaning": "less then or equals to"
    },
    {
      "condition": "eq",
      "meaning": "equals to"
    },
    {
      "condition": "neq",
      "meaning": "not equals to"
    }
  ]
}

Field: The field you want to filter. You can visit GET("baseUrl/allowed-query/fields/some-end-point") to see all the allowed fields. NOTE you'll need to fill /some-end-point with an actual endpoint the API you're consuming will tell you wish. Value: The value you want to search with. eg if the field is set to user.firstName and the value is set to smith it means {user.firstName: smith }" in JSON. Data Type: The data type of the field you want to search with. Currently, these are the accepted data types string | number | bool | date | dateTime. The data type date should be in this format 2006-01-02 YYYY-MM-DD YYYY(Year) MM(Month) DD(Day) and dateTime should be in this format 2006-01-02T15:04:05-07:00 YYYY(Year)='2006', MM(Month)='01', DD(Day)='02', HH(Hour 1 - 24)='15', MM(Minutes)='04', and UTC/GTM TIMEZONE(hour plus minus HH:MM) = '+00:00'. a date timestamp with timezone
"filters": [{
   "filterOption": "cn",
   "field": "firstName",
   "value": "foma",
   "dataType": "string"
}, {
   "filterOption": "cn",
   "field": "lastName",
   "value": "john",
   "dataType": "string"
}]

From the above JSON sample, we can interpret the filter as if firstName of data type string contains foma and lastName of data type string contains john
package main
import (
    "fmt"
    "strings"
)
type User struct {
    FirstName string
    LastName  string
}
var user User = User{
    FirstName: "will",
    LastName:  "smith",
}
func filter() bool {
    if strings.Contains(user.FirstName, "foma") && strings.Contains(user.LastName, "john") {
        return true
    }
    return false
}
func main() {
    fmt.Println("Result: ", filter())
}

You can copy and paste the above code here to run it. Note in the above code sample the if condition used && (and) not || (or) even though filters[1].searchCondition is set to OR as explained in Search Condition above. I'll modify the above JSON to this
"filters": [{
   "filterOption": "cn",
   "field": "firstName",
   "value": "foma",
   "dataType": "string"
}, {
   "filterOption": "cn",
   "field": "lastName",
   "value": "john",
   "dataType": "string"
}, {
   "filterOption": "cn",
   "field": "email",
   "value": "ui",
   "dataType": "string"
},{
   "filterOption": "gt",
   "field": "age",
   "value": "4",
   "dataType": "number"
}]

now this will be the code representation
package main
import (
    "fmt"
    "strings"
)
type User struct {
    FirstName string
    LastName  string
    Email     string
    Age       int
}
var user User = User{
    FirstName: "will",
    LastName:  "smith",
    Age:       4,
}
func filter() bool {
    if strings.Contains(user.FirstName, "foma") &&
        strings.Contains(user.LastName, "john") ||
        strings.Contains(user.Email, "ui") &&
            user.Age == 4 {
        return true
    }
    return false
}
func main() {
    fmt.Println("Result: ", filter())
}

You can copy and paste the above code here to run it. When mixing multiple AND and OR in one search Group filter the desired result may not show, we recommend using one AND and multiple OR(s) or one OR and multiple AND(s) eg
// RECOMMENDED
"filters": [{
   "searchCondition": "AND", // one "AND"
   "filterOption": "cn",
   "field": "firstName",
   "value": "foma",
   "dataType": "string"
}, {
   "searchCondition": "OR", // multiple "OR" .1
   "filterOption": "cn",
   "field": "lastName",
   "value": "john",
   "dataType": "string"
}, {
   "searchCondition": "OR", // multiple "OR" .2
   "filterOption": "cn",
   "field": "email",
   "value": "ui",
   "dataType": "string"
},{
   "searchCondition": "OR", // multiple "OR" .3
   "filterOption": "gt",
   "field": "age",
   "value": "4",
   "dataType": "number"
}]
// NOT RECOMMENDED
"filters": [{
   "searchCondition": "AND", // multiple "AND" .1
   "filterOption": "cn",
   "field": "firstName",
   "value": "foma",
   "dataType": "string"
}, {
   "searchCondition": "OR", // multiple "OR" .1
   "filterOption": "cn",
   "field": "lastName",
   "value": "john",
   "dataType": "string"
}, {
   "searchCondition": "AND", // multiple "AND" .2
   "filterOption": "cn",
   "field": "email",
   "value": "ui",
   "dataType": "string"
},{
   "searchCondition": "OR", // multiple "OR" .2
   "filterOption": "gt",
   "field": "age",
   "value": "4",
   "dataType": "number"
}]

This way the results are more predictable. If you want to make a query with multiple AND and OR this is where groups come in. You can see groups as putting brackets around if statements with several && and || to ensure proper conditional results. Modifying the above code to include groups we have this
{
  "filter":"true",
  "more":"true",
  "pageNumber": 1,
  "batchNumber": 10,
  "sort": "ASC",
  "orderBy" :"firsName",
  "groups": [{
    "filterGroupCondition":"AND",
      "filters": [{
          "searchCondition": "AND",
          "filterOption": "gt",
          "field": "age",
          "value": "4",
          "dataType": "number"
       }, {
          "searchCondition": "OR",
          "filterOption": "cn",
          "field": "firstName",
          "value": "foma",
          "dataType": "string"
       }, {
          "searchCondition": "OR",
          "filterOption": "cn",
          "field": "lastName",
          "value": "foma",
          "dataType": "string"
       }]
    }, {
    "filterGroupCondition":"OR",
      "filters": [{
          "searchCondition": "AND",
          "filterOption": "gt",
          "field": "age",
          "value": "4",
          "dataType": "number"
       }, {
          "searchCondition": "OR",
          "filterOption": "cn",
          "field": "email",
          "value": "foma",
          "dataType": "string"
       }, {
          "searchCondition": "OR",
          "filterOption": "cn",
          "field": "email",
          "value": "ui",
          "dataType": "string"
       }]
    }]
}

The above JSON sample will perform the following task
  1. if age is greater than 4 and and firstName contains "foma" or lastName contains "foma" Let's alias this as q1
  2. if age is greater than 4 and and email contains "foma" or email contains "ui" Let's alias this as q2
  3. Finally, the result will only include data in which q1 is true and q2 is true
This is how it will look in code
package main
import (
    "fmt"
    "strings"
)
type User struct {
    FirstName string
    LastName  string
    Email     string
    Age       int
}
var user User = User{
    FirstName: "will",
    LastName:  "smith",
    Age:       4,
}
func filter() bool {
    if (user.Age == 4 &&
        strings.Contains(user.FirstName, "foma") ||
        strings.Contains(user.LastName, "foma")) &&
        (user.Age == 4 &&
            strings.Contains(user.Email, "foma") ||
            strings.Contains(user.Email, "UI")) {
        return true
    }
    return false
}
func main() {
    fmt.Println("Result: ", filter())
}

You can copy and paste the above code here to run it. NOTE: The above query is an example, this kind of query can be optimized this way
{
  "filter":"true",
  "more":"true",
  "pageNumber": 1,
  "batchNumber": 10,
  "sort": "ASC",
  "orderBy" :"firsName",
  "groups": [{
    "filterGroupCondition":"AND",
      "filters": [{
          "searchCondition": "AND",
          "filterOption": "gt",
          "field": "age",
          "value": "4",
          "dataType": "number"
       }, {
          "searchCondition": "OR",
          "filterOption": "cn",
          "field": "firstName",
          "value": "foma",
          "dataType": "string"
       }, {
          "searchCondition": "OR",
          "filterOption": "cn",
          "field": "lastName",
          "value": "foma",
          "dataType": "string"
       }, {
          "searchCondition": "OR",
          "filterOption": "cn",
          "field": "email",
          "value": "foma",
          "dataType": "string"
       }, {
          "searchCondition": "OR",
          "filterOption": "cn",
          "field": "email",
          "value": "ui",
          "dataType": "string"
       }]
    }]
}

in code
func filter() bool {
    if user.Age == 4 &&
        (strings.Contains(user.FirstName, "foma") ||
            strings.Contains(user.LastName, "foma") ||
            strings.Contains(user.Email, "foma") ||
            strings.Contains(user.Email, "UI")) {
        return true
    }
    return false
}

NOTE: Search Condition and Filter Group Condition work the same. Also when using groups, group all your AND together and all your OR together. Example
// RECOMENDED
{
  "filter":"true",
  "more":"true",
  "pageNumber": 1,
  "batchNumber": 10,
  "sort": "ASC",
  "orderBy" :"firsName",
  "groups": [{
     "filterGroupCondition":"AND",
     "filters": [...]
  }, {
     "filterGroupCondition":"AND",
     "filters": [...]
  }, {
     "filterGroupCondition":"OR",
     "filters": [...]
  }, {
     "filterGroupCondition":"OR",
     "filters": [...]
  }]
}
// NOT RECOMENDED
{
  "filter":"true",
  "more":"true",
  "pageNumber": 1,
  "batchNumber": 10,
  "sort": "ASC",
  "orderBy" :"firsName",
  "groups": [{
     "filterGroupCondition":"AND",
     "filters": [...]
  }, {
     "filterGroupCondition":"OR",
     "filters": [...]
  }, {
     "filterGroupCondition":"OR",
     "filters": [...]
  }, {
     "filterGroupCondition":"AND",
     "filters": [...]
  }]
}