DEFINITIONS
USER: A user of the Work2020 software
API_USER: a developer, registered to access protected data from the USER using the OneTwo API
AUTHORIZATION_CODE: code retrieved by the API_USER after the USER authorizes the integration of the API_USER
ACCESS_TOKEN: code used by the API_USER to get data with the OneTwo API
REFRESH_TOKEN: code used by the API_USER to refresh an ACCESS_TOKEN
* MANDATORY
(*) MANDATORY ON CONDITION
HTTP RETURN CODES
200 OK
401 Unauthorized
404 Invalid call
409 Conflict (logical error)
AUTHENTICATION - OAUTH2
REGISTERING INTEGRATION
The API_USER must first register his integration with OneTwo. Contact OneTwo to receive your integration codes.
After registration, the API_USER will get assigned a unique clientId and clientSecret, which are used in the OAuth2 flow.
Note that the clientSecret key should not be shared or embedded in client-side code.
AUTHORIZATION FLOW
To get access to the users Work2020 data, the API_USER must get authorization from the USER.
Redirect users to the OneTwo2020 authorization page:
METHOD: Manual without a redirectUri
Handler: https://work.one-two.com/authorize
Type: GET
Parameters:
clientId*: the client_id you got from OneTwo when registering to use the OneTwo API
responseType*: must be 'code'
state: unique string to be passed back upon completion (optional)
Example:
If the user authorizes your integration, a popup window will be presented in Work2020. The USER has to manually send the AUTHORIZATION_CODE to the API_USER.
OBTAINING ACCESS TOKENS
After receiving the authorization code from the previous step, an access token can be requested to make API calls.
Note that the AUTHORIZATION_CODE can only be exchanged for an ACCESS_TOKEN once and expire 60 minutes after issuance. To exchange the code for an ACCESS_TOKEN, send an HTTP POST request to the following endpoint:
Handler: https://api.one-two.com/oauth2/access_token
Type: POST
Body (JSON):
{
"clientId"*: "issued when you register your integration",
"clientSecret"*: "issued when you register your integration",
"code"*: "the AUTHORIZATION_CODE",
"grantType"*: "must be 'authorization_code'"}
It is recommended to add content-type header to this request. Supported content type is:
application/json
You will receive a JSON response containing an ACCESS_TOKEN and REFRESH_TOKEN:
{
"tokenType": "Bearer",
"expiresIn": 3600,
"accessToken": "ACCESS_TOKEN",
"refreshToken": "REFRESH_TOKEN"
}
These access tokens are also known as bearer tokens. You can use this token to call API endpoints on behalf of the user, by adding it to the API request as an Authorization header.
type: API key
key: api_key
value: ACCESS_TOKEN
Access tokens expire shortly (usually 60 minutes) after they are issued for security reasons. If your integration needs to communicate with our API beyond the access token's lifespan, you will need to request a new ACCESS_TOKEN using the REFRESH_TOKEN which was issued with the ACCESS_TOKEN.
USING REFRESH TOKENS
If an ACCESS_TOKEN is expired you will receive a 401 Unauthorized. A new ACCESS_TOKEN and REFRESH_TOKEN can be obtained by sending an HTTP POST request to the following endpoint:
Handler: https://api.one-two.com/oauth2/refresh_token
Type: POST
Body (JSON):
{
"clientId"*: "issued when you register your integration",
"clientSecret"*: "issued when you register your integration",
"refreshToken"*: "the REFRESH_TOKEN",
"grantType"*: "must be 'refresh_token'"
}
You will receive a JSON response containing a new ACCESS_TOKEN and REFRESH_TOKEN:
{
"tokenType": "Bearer",
"expiresIn": 3600,
"accessToken": "ACCESS_TOKEN",
"refreshToken": "REFRESH_TOKEN"
}
A REFRESH_TOKEN will continue functioning until the user revokes them or uninstalls your integration.
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/executor/insert
Type: POST
Body (JSON):
{
“type”*:400110, value given by One Two
“barcodeType”(*): 10, value given by One Two, mandatory if barcode is empty. Used to autogenerate barcode.
“code”*: “TBA”,
“description”*: “Tom Baert”,
“comment”: “”,
"parentId": 0, meaning given by One Two
“barcode”(*): “/400099” mandatory if barcodeType is empty
}
Results:
200 – OK
{
“id”: 999,
“dateModified”: “2019-04-09T15:08:04”,
“barcode”: “/400099”
}
400 – NOK
{
“errorCode”: “1006”,
“errorMessage”: “Type does not exist”
}
errorCodes:
1006 - Type does not exist
1008 - code is mandatory
1004 - Code already exists
1005 - Barcode already exists
1012 - Barcode Type not found
1007 - Parent record not found
1011 - Description is mandatory
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/executor/update
Type: POST
Body (JSON):
{
"id"*: 999,
“type”:400110,
“code”: “TBA”,
“description”: “Tom Baert”,
“comment”: “”,
"parentId": 0,
“barcode”: “/400099”
}
Results:
200 – OK
{
“dateModified”: “2019-04-09T15:08:04”
}
400 – NOK
{
“errorCode”: “1006”,
“errorMessage”: “Type does not exist”
}
errorCodes:
1014 - id is mandatory
1004 - Code already exists
1005 - Barcode already exists
1007 - Parent record not found
1006 - Type does not exist
1001 - No record found with this ID
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/executor/delete
Type: POST
Body (JSON):
{
"id"*: 999,
“deleteAll”*: true/false true = all connected data of this executor will also be deleted
false = if there is connected data, the executor will not be deleted. Error = 1002
}
Results:
200 – OK
{
“dateModified”: “2019-04-09T15:08:04”
}
400 – NOK
{
“errorCode”: “1014”,
“errorMessage”: “id is mandatory”
}
errorCodes:
1014 - id is mandatory
1003 - deleteAll is mandatory
1001 - No record found with this ID
1002 - Still data connected with this record
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/executor/list
Type: POST
Body (JSON):
{
"perPage": 20, default 20, max 50
“nextBatch”(*): "xxx-xxx-xxxxxxx-xxx", empty on the first call
“type”*: 400110,
“filterId”(*): 999,
“filterCode”(*): “ABA”, wildcards ? and %
"filterDescription"(*): "Alain Bailleul", wildcards ? and %
“filterBarcode”(*): “/400099”,
"filterDateModified"(*): "2019-04-09T15:08:04" >= given date
}
Only one "filter..." field can be used. Filter fields are not used in subsequent calls.
If nextBatch is empty in the result, there are no more results for this call. If not empty, use the returned nextBatch field in the subsequent call(s).
Sorting is on the filter field, dateModified.
Results:
200 – OK
{
“nextBatch”: "xxx-xxx-xxxxxxx-xxx",
“executors”: [
{
"id": 999,
"type": 400110,
"code": "ABA",
"description": "Alain Bailleul",
"comment": "",
"barcode": "/400099",
"dateModified": "2019-04-09T15:08:04",
"parentId": 0
}, ...
]
}
400 – NOK
{
“errorCode”: “1006”,
“errorMessage”: “Type does not exist”
}
errorCodes:
1009 - type is mandatory
1006 - Type does not exist
1013 - Field types in json do not match expectations
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/group/insert
Type: POST
Body (JSON):
{
“type”*: 200110, value given by One Two
“barcodeType”(*): 20, value given by One Two, mandatory if barcode is empty. Used to autogenerate barcode.
“code”*: “PRJ1”,
“description”*: “Project 1”,
“comment”: “”,
"parentId": 0, meaning given by One Two
"number": 0,
“barcode”(*): “/200099” mandatory if barcodeType is empty
}
Results:
200 – OK
{
“id”: 999,
“dateModified”: “2019-04-09T15:08:04”,
“barcode”: “/200099”
}
400 – NOK
{
“errorCode”: “1006”,
“errorMessage”: “Type does not exist”
}
errorCodes:
1006 - Type does not exist
1008 - code is mandatory
1004 - Code already exists
1005 - Barcode already exists
1012 - Barcode Type not found
1007 - Parent record not found
1011 - Description is mandatory
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/group/update
Type: POST
Body (JSON):
{
"id"*: 999,
“type”: 200110,
“code”: “PRJ1”,
“description”: “Project 1”,
“comment”: “”,
"parentId": 0,
"number": 0,
“barcode”: “/200099”
}
Results:
200 – OK
{
“dateModified”: “2019-04-09T15:08:04”
}
400 – NOK
{
“errorCode”: “1006”,
“errorMessage”: “Type does not exist”
}
errorCodes:
1014 - id is mandatory
1004 - Code already exists
1005 - Barcode already exists
1007 - Parent record not found
1006 - Type does not exist
1001 - No record found with this ID
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/group/delete
Type: POST
Body (JSON):
{
"id"*: 999,
“deleteAll”*: true/false true = all connected data of this group will also be deleted
false = if there is connected data, the group will not be deleted. Error = 1002
}
Results:
200 – OK
{
“dateModified”: “2019-04-09T15:08:04”
}
400 – NOK
{
“errorCode”: “1014”,
“errorMessage”: “id is mandatory”
}
errorCodes:
1014 - id is mandatory
1003 - deleteAll is mandatory
1001 - No record found with this ID
1002 - Still data connected with this record
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/group/list
Type: POST
Body (JSON):
{
"perPage": 20, default 20, max 50
“nextBatch”(*): "xxx-xxx-xxxxxxx-xxx", empty on the first call
“type”*: 200110,
“filterId”(*): 999,
“filterCode”(*): “PRJ1”, wildcards ? and %
"filterDescription"(*): "Project 1", wildcards ? and %
“filterBarcode”(*): “/200099”,
"filterDateModified"(*): "2019-04-09T15:08:04" >= given date
}
Only one "filter..." field can be used. Filter fields are not used in subsequent calls.
If nextBatch is empty in the result, there are no more results for this call. If not empty, use the returned nextBatch field in the subsequent call(s).
Sorting is on the filter field, dateModified.
Results:
200 – OK
{
“nextBatch”: "xxx-xxx-xxxxxxx-xxx",
“groups”: [
{
"id": 999,
"type": 200110,
"code": "PRJ1",
"description": "Project 1",
"comment": "",
"barcode": "/200099",
"dateModified": "2019-04-09T15:08:04",
"parentId": 0,
"number": 0
}, ...
]
}
400 – NOK
{
“errorCode”: “1006”,
“errorMessage”: “Type does not exist”
}
errorCodes:
1009 - type is mandatory
1006 - Type does not exist
1013 - Field types in json do not match expectations
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/item/insert
Type: POST
Body (JSON):
{
“type”*: 500110, value given by One Two
“barcodeType”(*): 80, value given by One Two, mandatory if barcode is empty. Used to autogenerate barcode.
“code”*: “ART1”,
“description”*: “Article 1”,
“comment”: “”,
"parentId": 0, meaning given by One Two
"inputType"*: 1, value given by One Two
"purchasePrice": 10,
"salesPrice": 15,
“barcode”(*): “/500099” mandatory if barcodeType is empty
}
Results:
200 – OK
{
“id”: 999,
“dateModified”: “2019-04-09T15:08:04”,
“barcode”: “/500099”
}
400 – NOK
{
“errorCode”: “1006”,
“errorMessage”: “Type does not exist”
}
errorCodes:
1006 - Type does not exist
1008 - code is mandatory
1004 - Code already exists
1005 - Barcode already exists
1012 - Barcode Type not found
1007 - Parent record not found
1015 - inputType is mandatory
1016 - Input Type does not exist
1011 - Description is mandatory
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/item/update
Type: POST
Body (JSON):
{
"id"*: 999,
“type”: 500110,
“code”: “ART1”,
“description”: “Article 1”,
“comment”: “”,
"parentId": 0,
"inputType": 1,
"purchasePrice": 10,
"salesPrice": 15,
“barcode”: “/500099”
}
Results:
200 – OK
{
“dateModified”: “2019-04-09T15:08:04”
}
400 – NOK
{
“errorCode”: “1006”,
“errorMessage”: “Type does not exist”
}
errorCodes:
1014 - id is mandatory
1004 - Code already exists
1005 - Barcode already exists
1007 - Parent record not found
1006 - Type does not exist
1001 - No record found with this ID
1016 - Input Type does not exist
DELETING AN ITEM
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/item/delete
Type: POST
Body (JSON):
{
"id"*: 999,
“deleteAll”*: true/false true = all connected data of this item will also be deleted
false = if there is connected data, the item will not be deleted. Error = 1002
}
Results:
200 – OK
{
“dateModified”: “2019-04-09T15:08:04”
}
400 – NOK
{
“errorCode”: “1014”,
“errorMessage”: “id is mandatory”
}
errorCodes:
1014 - id is mandatory
1003 - deleteAll is mandatory
1001 - No record found with this ID
1002 - Still data connected with this record
RETRIEVING ITEMS WITH FILTER
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/item/list
Type: POST
Body (JSON):
{
"perPage": 20, default 20, max 50
“nextBatch”(*): "xxx-xxx-xxxxxxx-xxx", empty on the first call
“type”*: 500110,
“filterId”(*): 999,
“filterCode”(*): “ART1”, wildcards ? and %
"filterDescription"(*): "Article 1", wildcards ? and %
“filterBarcode”(*): “/500099”,
"filterDateModified"(*): "2019-04-09T15:08:04" >= given date
}
Only one "filter..." field can be used. Filter fields are not used in subsequent calls.
If nextBatch is empty in the result, there are no more results for this call. If not empty, use the returned nextBatch field in the subsequent call(s).
Sorting is on the filter field, dateModified.
Results:
200 – OK
{
“nextBatch”: "xxx-xxx-xxxxxxx-xxx",
“items”: [
{
"id": 999,
"type": 500110,
"code": "ART1",
"description": "Article 1",
"comment": "",
"barcode": "/500099",
"dateModified": "2019-04-09T15:08:04",
"parentId": 0,
"inputType": 1,
"purchasePrice": 10,
"salesPrice": 15
}, ...
]
}
400 – NOK
{
“errorCode”: “1006”,
“errorMessage”: “Type does not exist”
}
errorCodes:
1009 - type is mandatory
1006 - Type does not exist
1013 - Field types in json do not match expectations
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/item/delete
Type: POST
Body (JSON):
{
"id"*: 999,
“deleteAll”*: true/false true = all connected data of this item will also be deleted
false = if there is connected data, the item will not be deleted. Error = 1002
}
Results:
200 – OK
{
“dateModified”: “2019-04-09T15:08:04”
}
400 – NOK
{
“errorCode”: “1014”,
“errorMessage”: “id is mandatory”
}
errorCodes:
1014 - id is mandatory
1003 - deleteAll is mandatory
1001 - No record found with this ID
1002 - Still data connected with this record
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/item/list
Type: POST
Body (JSON):
{
"perPage": 20, default 20, max 50
“nextBatch”(*): "xxx-xxx-xxxxxxx-xxx", empty on the first call
“type”*: 500110,
“filterId”(*): 999,
“filterCode”(*): “ART1”, wildcards ? and %
"filterDescription"(*): "Article 1", wildcards ? and %
“filterBarcode”(*): “/500099”,
"filterDateModified"(*): "2019-04-09T15:08:04" >= given date
}
Only one "filter..." field can be used. Filter fields are not used in subsequent calls.
If nextBatch is empty in the result, there are no more results for this call. If not empty, use the returned nextBatch field in the subsequent call(s).
Sorting is on the filter field, dateModified.
Results:
200 – OK
{
“nextBatch”: "xxx-xxx-xxxxxxx-xxx",
“items”: [
{
"id": 999,
"type": 500110,
"code": "ART1",
"description": "Article 1",
"comment": "",
"barcode": "/500099",
"dateModified": "2019-04-09T15:08:04",
"parentId": 0,
"inputType": 1,
"purchasePrice": 10,
"salesPrice": 15
}, ...
]
}
400 – NOK
{
“errorCode”: “1006”,
“errorMessage”: “Type does not exist”
}
errorCodes:
1009 - type is mandatory
1006 - Type does not exist
1013 - Field types in json do not match expectations
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/registration/list
Type: POST
Body (JSON):
{
"perPage": 20, default 20, max 50
“nextBatch”(*): "xxx-xxx-xxxxxxx-xxx", empty on the first call
“type”*: 700110,
“filterId”(*): 999,
“filterParentId”(*): 999,
“filterExecutorId”(*): 999,
“filterExecutorCode”(*): “ABA”, wildcards ? and %
“filterGroupId”(*): 999,
“filterGroupCode”(*): “PRJ1”, wildcards ? and %
“filterItemId”(*): 999,
“filterItemCode”(*): “ART1”, wildcards ? and %
"filterDateModified"(*): "2019-04-09T15:08:04" >= given date
}
Only one "filter..." field can be used. Filter fields are not used in subsequent calls.
If nextBatch is empty in the result, there are no more results for this call. If not empty, use the returned nextBatch field in the subsequent call(s).
Sorting is on date, filter field, dateModified.
Results:
200 – OK
{
“nextBatch”: "xxx-xxx-xxxxxxx-xxx",
“registrations”: [
{
"id": 999,
"parentId": 0,
"type": 700110,
"dateIso": "2019-04-09T00:00:00",
"timeStamp": "2019-04-09T10:17:50",
"timeStampTZ": "Europe/Brussels",
"executorId": 999,
"executorCode": "ABA",
"groupId": 999,
"groupCode": "PRJ1",
"itemID": 999,
"itemCode": "ART1",
"item02Id": 0,
"item02Code": "",
"comment": "my comment",
"time01": "2020-06-10T09:00:00",
"time01Tz": "Europe/Paris",
"time02": "2020-06-10T10:15:00",
"time02Tz": "Europe/Paris",
"inputType": 1,
"input": "09:00 - 10:15",
"inputUnitId": 0,
"inputUnitCode": "",
"value": 4500.0000,
"valueUnitId": 0,
"valueUnitCode": "",
"output": "01:15",
"outputUnitId": 0,
"outputUnitCode": "",
"purchasePrice": 10,
"purchasePriceUnitId": 0,
"purchasePriceUnitCode": "",
"salesPrice": 15,
"salesPriceUnitId": 0,
"salesPriceUnitCode": "",
"totalPurchasePrice": 100,
"totalSalesPrice": 150,
"dateModified": "2019-04-09T15:08:04",
}, ...
]
}
400 – NOK
{
“errorCode”: “1006”,
“errorMessage”: “Type does not exist”
}
errorCodes:
1009 - type is mandatory
1006 - Type does not exist
1013 - Field types in json do not match expectations
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/scanner/assign
Type: POST
Body (JSON):
{
“scannerCode”*: "ot-2404301951373438353031",
“executorId”*: 5
}
Results:
200 – OK
400 – NOK
{
“errorCode”: “1017”,
“errorMessage”: “Scanner not found”
}
errorCodes:
1017 - Scanner not found
1018 - Executor not found
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/scanner/unassign
Type: POST
Body (JSON):
{
“scannerCode”*: "ot-2404301951373438353031"
}
Results:
200 – OK
400 – NOK
{
“errorCode”: “1017”,
“errorMessage”: “Scanner not found”
}
errorCodes:
1017 - Scanner not found
1019 - Scanner already free
Header: Bearer Token with ACCESS_TOKEN as value
Handler: https://api.one-two.com/v1/types/{type}
Type: GET
{type}:
executor
group
item
input
registration
Results:
200 – OK
[
{
"id": 200110,
"code": "Werknemers",
"description": "Actieve Werknemers"
}, ...
]
400 – NOK
{
“errorCode”: “1020”,
“errorMessage”: “Type not found”
}
errorCodes:
1020 - Type not found
Materiaal registratie oplossingen