The Research Drive Dashboard includes an API, which supports the same requests as the web environment makes.
For the API, the same rights apply to your account compared to the web environment.
This page provides cURL request examples. You can also use programming languages like Python to programmatically access the Research Drive Dashboard.
A complete list of calls can be found on the designated API documentation page, which includes additional example requests.
The API documentation page can be founded at https://<your-environment-url>/dashboard/api/documentation
To access the Dashboard API, you must create an access token for your account.
1. On the dashboard, click on your user name in the bottom left corner. 
2. On the Account tab, toggle the API setting to enable it.

3. A pop-up appears with your API token. Copy and save it, it will only be shown once.

With your API access token, you're able to request your account details.
curl -X 'GET' 'https://<environment_url>/dashboard/api/me' \ -H 'accept: application/json' \ -H 'Accept-Language: en' \ -H 'Authorization: Bearer <your-access-token>'
Example response;
{
"data": {
"id": 2075,
"username": "dashboardadmin1",
"name": "dashboardadmin1",
"email": "None",
"backend": {
"value": "local",
"trans": "Local"
},
"mfa": {
"value": "disabled",
"trans": "Disabled"
},
"description": null,
"last_login": null,
"status": {
"value": "active",
"trans": "Active"
},
"inviter": false,
"max_groups": null,
"create_date": "2022-12-06 15:01:02",
"change_date": "2023-02-06 13:40:37",
"is_application_account": true,
"is_surf_admin": false,
"is_portal_admin": true,
"is_contract_admin": false,
"application_account": {
"id": 790,
"username": "dashboardadmin1",
"role": {
"value": "portal_admin",
"trans": "Portal admin"
},
"is_surf_admin": false,
"is_portal_admin": true
},
"groups": [
{
"id": 2294,
"username": "project_x",
"name": "Project-X",
"email": "None",
"backend": {
"value": "local",
"trans": "Local"
},
"mfa": null,
"description": "This is test",
"last_login": null,
"status": {
"value": "active",
"trans": "Active"
},
"inviter": false,
"max_groups": null,
"create_date": "2023-01-30 23:17:39",
"change_date": "2023-02-06 13:40:37",
"groups_membership": {
"id": 55865204,
"shared_from": 2294,
"shared_with": 2075,
"role": {
"value": "member",
"trans": "Member"
},
"is_projectfolder_owner": false,
"is_member": true
}
}
],
"contracts": []
},
"auth": {
"can_store_account": true,
"can_store_contract": true,
"can_store_any_functional_account": true
},
"message": "Successfully retrieved user."
}
Retrieval of all account, including configuration and usage information.
curl -X 'GET' 'https://<environment_url>/dashboard/api/account' \ -H 'accept: application/json' \ -H 'Accept-Language: en' \ -H 'Authorization: Bearer <your-access-token>'
Example response;
{
"data": [
{
"id": 2339,
"username": "JfDa1eozv7ZvPpG4Y73XDiEHQ982FEnYMYTDOjKY",
"name": "John Doe",
"email": "john@doe.nl",
"backend": null,
"mfa": null,
"description": null,
"last_login": null,
"status": {
"value": "new",
"trans": "New"
},
"inviter": false,
"max_groups": null,
"create_date": "2023-02-16 09:28:47",
"change_date": null,
"contract_id": "KlantX"
},
{
"id": 2168,
"username": "pietje@puk.nl",
"name": "Pietje Puk",
"email": "pietje@puk.nl",
"backend": {
"value": "institutional",
"trans": "Institutional"
},
"mfa": null,
"description": "wijzig meerdere velden tegelijk",
"last_login": null,
"status": {
"value": "active",
"trans": "Active"
},
"inviter": false,
"max_groups": null,
"create_date": "2022-12-16 09:24:55",
"change_date": "2023-02-06 13:40:37",
"contract_id": "default",
"end_date": "2020-03-28"
},
..
..
],
"order_directions": [
{
"value": "asc"
},
{
"value": "desc"
}
],
"message": "Accounts retrieved."
}
Retrieval of a specific account, including configuration and usage information.
curl -X 'GET' 'https://<environment_url>/dashboard/api/account/2168' \ -H 'accept: application/json' \ -H 'Accept-Language: en' \ -H 'Authorization: Bearer <your-access-token>'
Example response;
{
"data": {
"id": 2168,
"username": "pietje@puk.nl",
"name": "Pietje Puk",
"email": "pietje@puk.nl",
"backend": {
"value": "institutional",
"trans": "Institutional"
},
"mfa": null,
"description": "wijzig meerdere velden tegelijk",
"last_login": null,
"status": {
"value": "active",
"trans": "Active"
},
"invited_by": {
"id": 628,
"username": "johnd",
"name": "John Doe",
"email": "John.Doe@surf.nl",
"backend": {
"value": "local",
"trans": "Local"
},
"mfa": {
"value": "disabled",
"trans": "Disabled"
},
"description": null,
"last_login": null,
"status": {
"value": "active",
"trans": "Active"
},
"inviter": false,
"max_groups": null,
"create_date": "2020-01-13 11:54:01",
"change_date": "2023-02-06 13:40:37"
},
"inviter": false,
"max_groups": null,
"create_date": "2022-12-16 09:24:55",
"change_date": "2023-02-06 13:40:37",
"is_application_account": null,
"is_surf_admin": null,
"is_portal_admin": null,
"application_account": null,
"storage": {
"id": 2138,
"type": {
"value": "personal",
"trans": "Personal"
},
"usage": {
"value": 0,
"trans": "0.00 GB"
},
"quotum": {
"value": 0,
"trans": "0.00 GB"
},
"status": {
"value": "active",
"trans": "Active"
},
"last_update": null,
"contract": {
"id": 6,
"contract_id": "default",
"owner": "Jane Doe",
"owner_email": "Jane@Doe.nl",
"contact": null,
"description": "Default contract",
"quotum": {
"value": 30000,
"trans": "30 TB"
},
"start_date": "2019-03-14",
"end_date": "2020-03-28",
"status": {
"value": "active",
"trans": "Active"
},
"internal": 0,
"ocgroup": null,
"remove_period": {
"value": 90
},
"inviter": true,
"strictaudit": false,
"invitation_whitelist": null,
"quotum_option": [
{
"value": 1,
"trans": "500 GB",
"quotum": 500
},
{
"value": 2,
"trans": "1000 GB",
"quotum": 1000
},
{
"value": 16,
"trans": "10 GB",
"quotum": 10
},
{
"value": 32,
"trans": "25 GB",
"quotum": 25
},
{
"value": 64,
"trans": "50 GB",
"quotum": 50
},
{
"value": 128,
"trans": "Custom input",
"quotum": null
},
{
"value": 256,
"trans": "100 GB",
"quotum": 100
}
],
"max_groups": 0,
"accounts": [],
"storages_sum_usage": {
"value": 320.238141642,
"trans": "320.24 GB"
},
"storages_sum_quotum": {
"value": 28399,
"trans": "28.4 TB"
}
}
},
"services": [
{
"id": 6,
"service": "Jupyter Hub",
"description": "",
"ocgroup": "jupyter"
},
{
"id": 9,
"service": "Dashboard",
"description": "Research Drive Dashboard",
"ocgroup": "dashboard"
},
],
"groups": [
{
"id": 2309,
"username": "pietjespuk_atvnistz",
"name": "PietjesPuk",
"email": "None",
"backend": {
"value": "local",
"trans": "Local"
},
"mfa": null,
"description": "Test Example",
"last_login": null,
"status": {
"value": "active",
"trans": "Active"
},
"inviter": false,
"max_groups": null,
"create_date": "2023-02-03 08:39:38",
"change_date": "2023-02-06 13:40:37",
"groups_membership": {
"id": 55865228,
"shared_from": 2309,
"shared_with": 2168,
"role": {
"value": "projectfolder_owner",
"trans": "Projectfolder owner"
},
"is_projectfolder_owner": true,
"is_member": false
}
},
{
"id": 2312,
"username": "test_uzgqfkiz",
"name": "Test",
"email": "None",
"backend": {
"value": "local",
"trans": "Local"
},
"mfa": null,
"description": null,
"last_login": null,
"status": {
"value": "active",
"trans": "Active"
},
"inviter": false,
"max_groups": null,
"create_date": "2023-02-03 10:50:19",
"change_date": "2023-02-06 13:40:37",
"groups_membership": {
"id": 55865231,
"shared_from": 2312,
"shared_with": 2168,
"role": {
"value": "projectfolder_owner",
"trans": "Projectfolder owner"
},
"is_projectfolder_owner": true,
"is_member": false
}
}
]
},
"auth": {
"is_inviter": false,
"is_contract_admin": false,
"can_update": true,
"can_update_status": [
{
"value": "inactive",
"trans": "Inactive"
},
{
"value": "remove",
"trans": "Remove"
}
],
"can_attach_contract": true,
"can_attach_any_service": true,
"can_store_personal_access_token": false,
"can_destroy_personal_access_token": false,
"can_update_setting": true,
"can_store_invite": false,
"can_destroy_mfa": false,
"can_update_password": false
},
"message": "Account retrieved."
}
Update the account status of a specific account.
- userid: Replace userid with the uniq numeric userid of the user account. Example: 2168
- status: Replace status with the intended status. This can be; active, inactive, remove or force_remove
curl -X 'PUT' 'https://<environment_url>/dashboard/api/account/<userid>/status/<status>' \ -H 'accept: application/json' \ -H 'Accept-Language: en' \ -H 'Authorization: Bearer <your-access-token>'
Example response;
{
"message": "Account blocked."
}
Send a new user invite to user John Doe
curl -X 'POST' 'https://<environment_url>/dashboard/api/account' \
-H 'accept: application/json' \
-H 'Accept-Language: en' \
-H 'Authorization: Bearer <your-access-token>' \
-H 'Content-Type: application/json' \
-d '{
"name": "John Doe",
"email": "John@Doe.nl"
}'
Example response;
{
"message": "Account stored."
}
Retrieval of all account, including configuration and usage information.
curl -X 'GET' 'https://<environment_url>/dashboard/api/functional-account' \ -H 'accept: application/json' \ -H 'Accept-Language: en' \ -H 'Authorization: Bearer <your-access-token>'
Example response;
{
"data": [
{
"id": 14060,
"name": "Team Space",
"description": "Project space",
"owner_name": "Janssen, J.J. (Jan)",
"status": {
"value": "active",
"trans": "Active"
},
"usage": {
"value": 0,
"trans": "0.00 GB"
},
"quotum": {
"value": 5000,
"trans": "5 TB"
},
"strictaudit": {
"value": 0,
"trans": "No"
},
"change_date": "2023-10-19 00:17:08",
"contract_id": "Contract_XYZ",
"contract_end_date": "2025-08-25",
"create_date": "2023-10-19 00:05:21",
"end_date": null,
"costcenter": null
},
{
"id": 14050,
"name": "Researchdrive projectfolder",
"description": null,
"owner_name": "J. Doe",
"status": {
"value": "active",
"trans": "Active"
},
"usage": {
"value": 152.6502245,
"trans": "152.65 GB"
},
"quotum": {
"value": 5000,
"trans": "5 TB"
},
"strictaudit": {
"value": 0,
"trans": "No"
},
"change_date": "2023-10-16 14:17:48",
"contract_id": "ContractABC",
"contract_end_date": "2024-10-03",
"create_date": "2023-10-16 13:16:46",
"end_date": null,
"costcenter": null
}, ..
..
],
"order_directions": [
{
"value": "asc"
},
{
"value": "desc"
}
],
"message": "Accounts retrieved."
}
In the example below, we create a new project folder. An explanation of the values;
- Name: Projectfolder name
- Account.id: May be the unique id or the username of the account which will become project folder admin
- Description: Project description, visible only in Dashboard. (Not a required field)
- contract.id: The unique id of the contract, to which it can be attached.
Note: the contract must be active, have sufficient storage available and an end date in the future. - Quotum: amount of allocated storage capacity in GB
curl -X 'POST' 'https://<environment_url>/dashboard/api/functional-account' \
-H 'accept: application/json' \
-H 'Accept-Language: en' \
-H 'Authorization: Bearer <your-access-token>' \
-H 'Content-Type: application/json' \
-d '{
"name": "NameOfMyProject",
"account": {
"id": "j.doe@username.here"
},
"description": "Project Description Which is not Requird",
"contract": {
"id": 123
},
"quotum": 10
}'
Example response;
{
"message": "Projectfolder stored."
}
In the example below, we will change the prokectfolder admin for an existing project folder.
- Step 1: find the unique ID of the project folder.
Additional search criteria are possible to easily lookup the project, for example project status, linked contract or a search term.
Example;curl -X 'GET' \ 'https://<environment_url>/dashboard/api/functional-account?status%5B%5D=active&search=Doe' \ -H 'accept: application/json' \ -H 'Accept-Language: en' \ -H 'Authorization: Bearer <your-access-token>'
Response:{ "data": [ { "id": 9404, "name": "Project of John Doe", "description": null, "owner_name": "John Doe", "status": { "value": "active", "trans": "Active" }, "usage": { "value": 0, "trans": "0.00 GB" }, "quotum": { "value": 5, "trans": "5 GB" }, "strictaudit": { "value": 0, "trans": "No" }, "change_date": "2025-12-12 12:54:44", "contract_id": "DEFAULT", "contract_end_date": "2032-12-31", "create_date": "2025-12-12 12:54:15", "end_date": null, "costcenter": null }, { "id": 9394, "name": "Project of Jane Doe", "description": null, .. .. - Change project Project of John Doe with id 9404 of projectadmin.
Requires
a. Unique ID of the projectfolder in the URL
b. Account.id: May be the unique id or the username of the account which will become project folder admincurl -X 'PUT' \ 'https://<environment_url>/dashboard/api/functional-account/9404/account' \ -H 'accept: application/json' \ -H 'Accept-Language: en' \ -H 'Content-Type: application/json' \ -H 'Authorization: Bearer <your-access-token>' \ -d '{ "account": { "id": "Piet.deWit@surf.nl" } }'Example response;
{ "message": "Account stored." }
Retrieval of all contracts, including configuration and usage information.
curl -X 'GET' 'https://<environment_url>/dashboard/api/contract' \ -H 'accept: application/json' \ -H 'Accept-Language: en' \ -H 'Authorization: Bearer <your-access-token>'
Example response;
{
"data": [
{
"id": 149,
"contract_id": "test8",
"owner": "dashboardadmin1",
"owner_email": "dash@admin.nl",
"contact": [],
"description": "test",
"quotum": {
"value": 500,
"trans": "500 GB"
},
"start_date": "2023-02-15",
"end_date": "2023-03-08",
"status": {
"value": "active",
"trans": "Active"
},
"internal": 0,
"ocgroup": null,
"remove_period": {
"value": 30
},
"inviter": true,
"strictaudit": false,
"invitation_whitelist": null,
"quotum_option": [
{
"value": 256,
"trans": "100 GB",
"quotum": 100
}
],
"max_groups": 2,
"storages_sum_usage": {
"value": 0,
"trans": "0.00 GB"
},
"storages_sum_quotum": {
"value": 200,
"trans": "200 GB"
}
},
{
"id": 146,
"contract_id": "Test123",
"owner": "tom",
...
...
],
"order_directions": [
{
"value": "asc"
},
{
"value": "desc"
}
],
"message": "Accounts retrieved."
}
The API is limited to being able to return up to a maximum of 1000 records in once. This is done because loading the many relation takes some time.
It is faster to loop over multiple lists with smaller number of records.
Example what could work;
for i in `seq 1 $(curl -s -X GET '<environment_url>/dashboard/api/account?per_page=250' \
-H 'accept: application/json' -H 'Accept-Language: en' \
-H 'Authorization: <your-access-token>' | jq .meta.last_page)`
do
echo "Loop over page: ${i}"
curl -X GET "https://<environment_url>/dashboard/api/account?page=${i}&per_page=250" \
-H "accept: application/json" \
-H "Accept-Language: en" \
-H "Authorization: <your-access-token>" | jq .data
done
The above was done on a Unix machine. In this example we make use of the JSON processor JQ (https://jqlang.github.io/jq/)
Explaining what happens here;
We do an first request to the endpoint, where we parse the total number op pages.
curl -s -X GET '<environment_url>/dashboard/api/account?per_page=250' \ -H 'accept: application/json' -H 'Accept-Language: en' \ -H 'Authorization: <your-access-token>' | jq .meta.last_page
We loop over the result of this number of pages;
for i in `seq 1 $(curl -s -X GET '<environment_url>/dashboard/api/account?per_page=250' \ -H 'accept: application/json' -H 'Accept-Language: en' \ -H 'Authorization: <your-access-token>' | jq .meta.last_page)` do echo "Loop over page: ${i}" doneCollect the data records of each page
for i in `seq 1 $(curl -s -X GET '<environment_url>/dashboard/api/account?per_page=250' \ -H 'accept: application/json' -H 'Accept-Language: en' \ -H 'Authorization: <your-access-token>' | jq .meta.last_page)` do echo "Loop over page: ${i}" curl -X GET "https://<environment_url>/dashboard/api/account?page=${i}&per_page=250" \ -H "accept: application/json" \ -H "Accept-Language: en" \ -H "Authorization: <your-access-token>" | jq .data >> /tmp/api_results.json done
This is just a small example with CURL. With languages like Python, this can easily be used.
Dit is een voorbeeld om met gebruik van de programmeertaal Python een account van status te kunnen wisselen.
Dit is een in 5-minuten in elkaar gezet script, gebruik dit niet in productie omdat fout afhandeling er niet in zit!
Een snel voorbeeld ;
#!/usr/bin/env python
import os
import argparse
import requests
import json
###
# Variables
###
env_url = "environment_url" # Your Environment URL Here
api_token = "" # Your AccessToken Here
###
# Argument Parser from command-line
###
parser = argparse.ArgumentParser()
parser.add_argument("-d", "--debug", action="count", default=0, help="Enable debug output")
parser.add_argument("--active", action="count", default=0, help="Activate user")
parser.add_argument("--remove", action="count", default=0, help="Remove user")
parser.add_argument("--disable", action="count", default=0, help="Disable user")
parser.add_argument("-u", "--user", type=str, required=True, help="Username of user to lookup")
args = parser.parse_args()
# Set input in readable string
debug = args.debug
input_user = args.user
activate_account = args.active
remove_account = args.remove
disable_account = args.disable
###
# Lookup where an user lives based on emailaddress or username
###
def get_user_by_username(user):
try:
if debug == 1:
print(f"DEBUG - try to lookup user: {user}")
url = f"https://{env_url}/dashboard/api/account?search={user}"
headers = {
'Accept': 'application/json',
'Authorization': 'Bearer ' +str(api_token ),
}
response = requests.get(url, headers=headers)
response_code = response.raise_for_status()
if debug == 1:
print("DEBUG - Status Code", response.status_code)
print("DEBUG - Response ", response.text)
# load the json to a string
api_json = json.dumps(response.json())
api_resp = json.loads(api_json)
return(api_resp['data'])
except requests.exceptions.HTTPError as err:
raise SystemExit(err)
def set_user_status_by_id(userid,status):
try:
if debug == 1:
print(f"DEBUG - try to set user {userid} to status {status}")
url = f"https://{env_url}/dashboard/api/account/{userid}/status/{status}"
headers = {
'Accept': 'application/json',
'Authorization': 'Bearer ' +str(api_token ),
}
response = requests.put(url, headers=headers)
response_code = response.raise_for_status()
if debug == 1:
print("DEBUG - Status Code", response.status_code)
print("DEBUG - Response ", response.text)
if not response.status_code in [100, 200, 201]:
print(f"Request for {userid} was unsuccesful.")
raise
return(response.text)
except requests.exceptions.HTTPError as err:
raise SystemExit(err)
###
# Main
###
def main():
account = get_user_by_username(input_user)
if debug == 1:
print(f"Account details: {account}")
if len(account) > 1:
print(f"Got more then 1 result.")
exit()
try:
account_id = account[0]['id']
print(f"Handle account {input_user} with uniq account id: {account_id}")
if activate_account == 1:
status = 'active'
set_user_status_by_id(account_id,status)
elif disable_account == 1:
status = 'inactive'
set_user_status_by_id(account_id,status)
elif remove_account == 1:
status = 'remove'
set_user_status_by_id(account_id,status)
except Exception as e:
print(f"Error during account handling. Error was {e}")
if __name__ == '__main__':
main()
Dit is een in 5-minuten in elkaar gezet script, gebruik dit niet in productie omdat fout afhandeling er niet in zit!
- No labels