# SimTree API documentation

Revision: 2026-04-23

User email, password and schema are required to call the API.

Base address: <https://api-dot-secure-ripple-312910.nw.r.appspot.com>

## Headers

* Content-Type: application/json

All API calls except authentication requires:

* dn-customer-schema: **name of your schema**
* Authorization: Bearer **your accesstoken**

## Authentication

### POST /authentication/user

Request:

```json
{
  "strategy": "local", // string: local
  "email": "", // string: your email
  "password": "" // string: your password
}
```

or

```json
{
   "strategy": "local", // string: local
   "action": "refresh", // string: refresh
   "refresh_token": "" // string: your refreshToken
}
```

Response:

```json
{
"accessToken": "", // string max length: 500 chars
"refreshToken": "", // string max length: 500 chars
"authentication":{"strategy":"local"},
"user":
  {
    "id": 1, // number: unique identifier for the user,
    "email": "", // string: email used to login, (deprecated)
    "name": "", // string: name of the user (deprecated)
  }
}
```

The refreshToken is valid for 4 days and the accessToken for a day.

## Affinities

### GET /affinity

Response:

```json
[
  {
    "id": 1, // number: unique identifier 
    "name": "", // string
  }
]
```

## Agent events

Kind of agent events:

* 0 = log in
* 1 = log out
* 2 = in rotation
* 3 = out of rotation

### GET /agent-event?limit=$1&switchId=$2

where

* $1 = max number of rows to return
* $2 = optional switch id for agent events to get

```json
[
  {
    "timestamp": "2023-09-20T09:59:59.000Z", // string: ISO 8601 datetime
    "kind": 1, // number: 0-3 defined above
    "employeeSwitchId": "a", // string: the id connected to the employee
    "reasonCode": "some text" // string|null: 
  }
]
```

### POST /agent-event

```json
[
  {
    "timestamp": "2023-09-20T09:59:59.000Z", // string: ISO 8601 datetime
    "kind": 1, // number: 0-3 defined above
    "employeeSwitchId": "a", // string: the id connected to the employee
    "reasonCode": "some text" // optional string
  }
]
```

returns

```json
{
  "added": 3 // number: number of agent events added, if the event already exists it is ignored.
}
```

### DELETE /agent-event?st=$1&fi=$2&switchId=$3

where

* $1 = ISO 8601 start time for the interval to delete
* $2 = ISO 8601 end time for the interval to delete
* $3 = optional switch id for agent events to delete

## Calls

### GET /calls?limit=$1&switchId$2&orderById=$3

where

* $1 = A number between 1 and 1000
* $2 = Optional. The id of the switch, default 1
* $3 = Optional. if it is the number 1 it returns the last inserted calls. Otherwise it returns the calls with highest 32 bit integer callid and then by last inserted call

```json
[
  {
    "callid":187148681, // number|null: if 32-bit id is used
    "calltype":4, // number: 3=abandoned, 4=answered
    "timestamp_utc":"2023-11-07T22:59:00.000Z", // string: time in utc
    "talk":29496, // number: talk time in milliseconds
    "wrap":9628, // number: wrap time in milliseconds
    "tag1":"52097", // string|null: 64 bit integer used in call grouping
    "tag2":"52097", // string|null: 64 bit integer used in call grouping
    "tag3":193, // number|null: 32 bit integer used in call grouping
    "callgroups":[3], // null|number[]: calculated call group ids that the call belongs to
    "textId":null, // string|null: if non 32-bit id is used
    "noc": //number|null|undefined: 32 bit number. Number of calls, if aggregated statistics is used 
  }
]
```

### POST /calls

Insert an array of calls. Limit to max 10000 calls so that the request size limit is not reached.
Calls with duplicate id are ignored. One can get the info about the last imported id or time in the api import-config.

```json
{
  "generateTextId": "false", // optional boolean: if an id will be generated to avoid duplicate 
  "switchId": 1, // optional number: 1 is default, corresponds to id 
  "calls": [{
    "callid": 85976182, // optional number|string: a unique identfier for the call, either a 32 bit number or a string
    "timestamp": "2022-03-15T22:33:00.000Z", // string: ISO 8601 datetime string. If no time zone is given, a time zone specified on the server is used.
    "wrap":247584, // number: 32bit integer of the wrap time in milliseconds
    "talk":202447, // number: 32bit integer of the talk time in milliseconds
    "tag1":25647, // optional number|string|null: 64 bit integer used in call grouping
    "tag2":25647, // optional number|string|null: 64 bit integer used in call grouping
    "tag3":70, // optional number|null: 32 bit integer used in call grouping
    "abandon":0, // number: 1 if call was abandoned, otherwise 0. In case of aggregated statistics it is the number abandoned calls. The abandonded calls should be included in noc so abandon <= noc. 
    "timeToAnswer":null, // optional number|null: time to answer in milliseconds
    "segments": [{"agent":"ABC","ring":3000,"talk":202447,"wrap":247584}], // optional array[]|null: array of employee switch id with ring, talk and wrap time per agent in milliseconds
    "noc": // optional number|null: 32 bit number. Number of calls, can be used if only aggregated statistics is available 
    },
    {
    "timestamp": "2022-03-15T22:33:00.000+00:00",
    "wrap":247584,
    "talk":202447,
    "tag1":25647,
    "abandon":1
    }
  ]
}
```

Response (if ok):

```json
{ 
  "ok": true
}
```

## Genesis agent events

Insert data with data from the result of POST /system/AgentTracker endpoint in WebSupervisor API. The request format to /system/AgentTracker is

```json
{
    "start": "2026-01-14T13:15",
    "end": "2026-01-16T13:15"
}

```

### POST /genesis-agent-tracker

```json
{
    "switchId": 1, // option number: the id of the switch in simTree to impprt to. Default 1
    "list": [] // array of data from property item1 of /system/AgentTracker result
}

```

returns

```json
{
  "added": 3 // number: number of agent events added, if the event already exists it is ignored.
}
```

## Genesis calls

Insert data with data from the result of POST /system/CallTracker endpoint in WebSupervisor API. The request format to /system/AgentTracker is

```json
{
    "start": "2026-01-14T13:15",
    "end": "2026-01-16T13:15"
}

```

### POST /genesis-call-tracker

```json
{
    "switchId": 1, // option number: the id of the switch in simTree to impprt to. Default 1
    "list": [] // array of data from property item1 of /system/CallTracker result
}

```

returns

```json
{
  "added": 3 // number: number of call added, if the call already exists it is ignored.
}
```

### POST /import-calls

Insert an array of calls. Limit to max 10000 calls so that the request size limit is not reached.
Calls with duplicate id are ignored. One can get the info about the last imported id or time in the api import-config.

```json
[
  {
  "callid": 85976182, // number|string: a unique identfier for the call, either a 32 bit number or a string
  "timestamp": "2022-03-15T22:33:00.000Z", // string: ISO 8601 datetime string. If no time zone is given, a time zone specified on the server is used.
  "wrap":247584, // number: 32bit integer of the wrap time in milliseconds
  "talk":202447, // number: 32bit integer of the talk time in milliseconds
  "tag1":25647, // optional number|string|null: 64 bit integer used in call grouping
  "tag2":25647, // optional number|string|null: 64 bit integer used in call grouping
  "tag3":70, // optional number|null: 32 bit integer used in call grouping
  "abandon":0, // number: 1 if call was abandoned, otherwise 0.
  "switchId":1, // optional number: 1 is default
  "timeToAnswer":null, // optional number|null: time to answer in milliseconds
  "segments": [{"agent":"ABC","ring":3000,"talk":202447,"wrap":247584}] // optional array[]|null: array of employee switch id with ring, talk and wrap time per agent in milliseconds
  },
  {
  "callid": "5tAds4",
  "timestamp": "2022-03-15T22:33:00.000+00:00",
  "wrap":247584,
  "talk":202447,
  "tag1":25647,
  "abandon":1
  }
]
```

Response (if ok):

```json
{ 
  "ok": true
}
```

## import-config

### GET /import-config/$1

where
$1 = The switch id that can be in Settings > Import statistics > Switches

```json
{
  "calls": // The object below or null
  {
  "lastTime":"2025-01-07T23:00:00.000Z", // string: ISO 8601 datetime string of the last imported or call or the time set in the user inteface.
  "lastTimeLocal":"2025-01-07T23:00:00", // string: ISO 8601 datetime string without time zone. Same time as in lastTime bu in the switch time zone
  "lastId":null, // number|null: The last inserted call id (if numeric id:s are used) 
  "lastTextId":null}, // string|null: The last inserted call id (if text id:s are used)
  "agentEvents": // The object below or null
  {
    "lastTime":"2025-01-05T23:00:00.000Z", // string: ISO 8601 datetime string of the last imported event or the time set in the user inteface.
    "lastTimeLocal":"2025-01-07T23:00:00" // string: ISO 8601 datetime string without time zone. Same time as in lastTime bu in the switch time zone
  }}
```

## Call groups/Skills

### GET /callgroups?includeConditions=1

?includeConditions=1 can be omitted. In that case conditions is not included in the result

```json
[
  {
    "id": 1, // number: unique identifier
    "name": "s1",
    "description": "",
    "slpercent": 80, // number: % sl target
    "slseconds": 20, // number: seconds for sl target
    "ccid": 1, // number: connect contact center/call center id
    "addWrap": null, // number|null: added constant wrap time
    "affinityId": null, // number|null: id for the affinity
    "prioSecondsInQueue": null, // smallint|null: queue priority
    "optimizationPriority": null, // smallint|null: priority in optimization
    "conditions": [
      {
        "id": 1, // number: unique id of the the condition
        "callgroupid": 1, // number: parent id, depricated
        "tag1min": "0", // string - BigInt
        "tag1max": "9999999", // string - BigInt
        "tag2min": "0", // string - BigInt
        "tag2max": "9999999", // string - BigInt
        "tag3min": 90, // number
        "tag3max": 91, // number
        "switchId": 1 // number: switch id used if one has multiple switched. Otherwise set to 1
      }
    ]
  }
]
```

### POST /callgroups

Request (creates a new call groupp)

```json
{
  "name": "test",
  "description": "",
  "slpercent": 80,
  "slseconds": 20,
  "addWrap": null,
  "ccid": 1, // number: id for the contact center/call center
  "affinityId": 1, // number|null: optional id for the affinity
  "prioSecondsInQueue": 0, // smallint|null: optional queue priority
  "optimizationPriority": null, // smallint|null: optional priority in optimization
  "conditionsToInsert": [
    {
      "switchId": 1,
      "tag1min": "1",
      "tag1max": "1",
      "tag2min": null,
      "tag2max": null,
      "tag3min": null,
      "tag3max": null
    }
  ],
  "conditionsToDelete": [],
  "conditionsToUpdate": []
}
```

Response (return id:s for the call group)

```json
{
  "id": 6, // number
  "newConditionIds": [
    5
  ] // number[]
}
```

### PATCH /callgroups/$1

Request (updates a call groupp, similar interface as POST)

```json
{
  "name": "test",
  "description": "",
  "slpercent": 80,
  "slseconds": 20,
  "addWrap": null,
  "ccid": 1,
  "affinityId": 1, // number|null: optional id for the affinity
  "prioSecondsInQueue": 0, // smallint|null: optional queue priority
  "optimizationPriority": null, // smallint|null: optional priority in optimization
  "conditionsToInsert": [],
  "conditionsToDelete": [
    5
  ],
  "conditionsToUpdate": [
    {
      "switchId": 1,
      "tag1min": "4",
      "tag1max": "6",
      "tag2min": null,
      "tag2max": null,
      "tag3min": null,
      "tag3max": null,
      "id": 6
    }
  ]
}
```

Response (return id:s for the call group)

```json
{
  "id": 6,
  "newConditionIds": []
}
```

## Contact centers / Call centers

### GET /callcenters

Response

```json
[
  {
    "id": 1, // number: unique identifier
    "name": "cc1", 
    "description": "",
    "tagIds": [] // number[]: list of tag id:s set on this contact center
  }
]
```

## Employees

### GET /employees?ccId=$1

where $1 = id of the contact center

Response:

```json
[
  {
    "id": 1, // number: unique identifier for the employee,
    "name": "test",
    "email": "",
    "switchid": "0", // string: ;-separated list of id:s used in the switch
    "rotations": 0, // number: deprecated
    "active": true, // boolean
    "ccid": 1, // number: id of contact center the employee belongs to
    "empid": "1", // string: text id to show in the program not required to be unique
    "userid": 7, // number|null: 
    "agreedWorkWeek": 2400, //number|null: minutes of agreed work per week
    "minWorkWeek": null, // number|null: in minutes
    "maxWorkWeek": null, // number|null: in minutes
    "optimizationOrder": 0, // number: 0,1,2,3
    "maxDaysInRow": null, // number|null
    "maxWeekendsInRow": null, // number|null
    "nightRest": null, // number|null: in minutes
    "address1": null, // string|null
    "address2": null, // string|null
    "address3": null, // string|null
    "phoneNum": null, // string|null
    "skills": [ 1, 3, 2 ], // number[]: list of call group id:s that the employee is skilled in
    "tagIds":, [] // number[]: list of tag id:s set on this employee
    "ghost": false, //boolean
    "username": null, // string|null, username used to log in to app
    "maxBOWeek": null, // number|null max allowed BO work per week in minutes, null means no limit
    "absenceDuration": null, // number|null duration in minutes for default absence task
    "hasMainApp": false // boolean|undefined, true if the employee has access to main app 
  }
]
```

### POST /employees

Request (creates a new employee)

```json
{
  "empid": "14", // string: text id to show in the program not required to be unique
  "ccid": 1, // number: id of contact center the employee belongs to
  "name": "test emp",
  "agreedWorkWeek": null,
  "minWorkWeek": null,
  "maxWorkWeek": null,
  "optimizationOrder": 0, // number: 0,1,2,3
  "maxDaysInRow": null,
  "maxWeekendsInRow": null,
  "nightRest": null,
  "email": "testemp@deepnumber.se", // email: should be unique
  "notify": false, // string: send notification email to the given email address (if useraname undefined or email = username)
  "switchid": null, // string: ;-separated list of id:s used in the switch
  "skills": [
    2,
    3
  ], // number[]: optional list of call group id:s that the employee is skilled in
  "active": true,
  "password": "", // null|string: password for logging in to the system
  "tagIds": [],
  "address1": null,
  "address2": null,
  "address3": null,
  "phoneNum": null,
  "ghost": false, // boolean|undefined
  "username": null, // string|null|undefined, username used to log in to app. if undefined email is used
  "maxBOWeek": null, // optional number|null max allowed BO work per week in minutes, null means no limit
  "absenceDuration": null // optional number|null duration in minutes for default absence task
}
```

Response

```json
{
  "id": 18, // number|null: created id if successful, null if not
  "userId": null, // number: created user id if email and password 
  "notifyResult": null, // boolean|null
  "emailAlreadyInUse": false // boolean, if true the username already exists and the employee is not created.
}
```

### PATCH /employees/$1

where $1 = id of the employee

Request (updates an employee)

```json
{
  "empid": "7",
  "ccid": 1,
  "name": "Emp 7",
  "agreedWorkWeek": null,
  "minWorkWeek": null,
  "maxWorkWeek": null,
  "optimizationOrder": 1,
  "maxDaysInRow": null,
  "maxWeekendsInRow": null,
  "nightRest": null,
  "email": "emp7@local_test",
  "notify": false,
  "switchid": null,
  "skills": [
    3
  ],  // number[]: optional list of call group id:s that the employee is skilled in
  "active": true,
  "password": "",
  "tagIds": [],
  "userid": null,
  "address1": null,
  "address2": null,
  "address3": null,
  "phoneNum": null,
  "ghost": false, // boolean|undefined
  "username": null, // string|null|undefined, username used to log in to app. if undefined email is used
  "maxBOWeek": null, // optional number|null max allowed BO work per week in minutes, null means no limit
  "absenceDuration": null // optional number|null duration in minutes for default absence task
}
```

Response

```json
{
  "id": 10, // number|null: sent in id
  "userId": null, // number: created user id if email and password 
  "notifyResult": null, // boolean|null
  "emailAlreadyInUse": false // boolean, if true the username already exists and the employee is not updated.
}
```

## Forecast

Insert or update data for retail forecast

### POST /forecast

Request

```json
{
  "skillId": 1, // number: id of the skill
  "rows": [
    {
      "dt": "2025-10-24", // string, ISO 8601 date
      "intraValues": [0,0,0,0,3,2,7,3,5,0,0,0] // number array, evenly spaced forecasted values during the day. Possible array sizes: 96, 48, 24, 12, 6, 4, 2, 1
    }
  ]
}
```

## Schedule

### GET /scheduletasks?st=$1&fi=$2&ccid=$3 or /scheduletasks?st=$1&fi=$2&empId=$4

* $1 = start of interval to fetch in ISO 8601 format
* $2 = end of interval to fetch in ISO 8601 format
* $3 = id of contact center to fetch
* $4 = id of the employee to fetch

Response (gets tasks which starts on the given interval)

```json
[
  {
    "id": 2401,  // number: unique identifier of the task,
    "empid": 2, // number: employee id
    "st": "2023-08-17T14:00:00.000Z", // string: ISO 8601 start time
    "fi": "2023-08-17T18:00:00.000Z", // string|null: ISO 8601 end time
    "tasktypeId": 1 // number: task type id
  }
]
```

### POST /scheduletasks

Request (creates/modifies/deletes schedule)

```json
{
  "create": [
    {
      "empid": 15, // number: employee id
      "st": "2023-08-20T07:00:00.000Z", // string: ISO 8601 start time
      "fi": "2023-08-20T11:00:00.000Z", // string: ISO 8601 start time
      "tasktypeId": 1 // id of the task type
    }
  ],
  "delete": [
    2474,
    2475
  ], // number[]: task id:s to delete
  "update": [
    {
      "empid": 14, // number: employee id
      "st": "2023-08-20T07:15:00.000Z", // string: ISO 8601 start time
      "fi": "2023-08-20T07:30:00.000Z", // string: ISO 8601 start time
      "tasktypeId": 2, // id of the task type
      "id": 2473 // id of the task to update
    }
  ],
  "requestReplies": [] // array of answered schedule requests
}
```

Response (status code 201 if successful, returns created tasks with)

```json
[
  {
    "id": 2578,
    "empid": 15,
    "st": "2023-08-20T07:00:00.000Z",
    "fi": "2023-08-20T11:00:00.000Z",
    "tasktypeId": 1
  }
]
```

## Task types

### GET /tasktypes

Response:

```json
[
  {
    "id": 1, // number: unique identifier 
    "name": "operator", // string
    "work": 100, // number|null: % contribution for operator tasks
    "paid": 100, // number|null: % contribution for payment tasks
    "schemecolor": "stroke1", // string: color used in the program
    "kind": 0, // number: 0=operator task, 1=break, 2=absence, 3=payment, 4=log, 5=inRotation, 6=correction, 7=clock
    "systemKind": 0, // number|null: system task that can't be deleted has non-null values
    "affinityId": null // number|null: identifier for the affinity
  }
]
```

## Users

Users to the main app. For the employee app see the Employees section.

### POST /users

```json
{
  "toDelete": [1, 2], // number[]: user id:s to delete,
  "toCreate": [
    {
      "name": "User a", // string: name of the user
      "email": "qwerty", // string: username, does not need to be an email
      "password": "zxcvbn", // string: password, of the new user
      "notify": false // optional boolean: a notifcation email is send to "email" if it is an actual email
    }
  ],
  "toPatch": [
    {
      "id": 1, // number: id of the user
      "name": "User a", // string: name of the user
      "email": "qwerty" // string: username, does not need to be an email
    }
  ],
  "requestReplies": [] // array of answered schedule requests
}
```

Response

```json
[
  {
    "created": [
      {
        "id": 1, // number, id of the created user
        "email": "qwerty", // string, username
        "notifyResult": null // boolean|null, if the notfication was successful
      }
    ],
    "errors": [
      {
        "email": "qwerty", // string, username where something went wrong
        "emailAlreadyExists": true // boolean, if the username is already in use
      }
    ]
  }
]
```
