NAV -image
bash javascript

Introduction

This documentation aims to provide all the information you need to work with our API.

Base URL

https://api-preprod.aetherdigitaltherapy.com

Authenticating requests

This API is authenticated by sending an Authorization header with the value "Bearer {ACCESS_TOKEN}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

Token based authentication

You can retrieve your access token by calling api/login endpoint.

Access tokens are valid 7 days, then expire. You can obtain new access token with expiring access token by calling /api/token/refresh. You can only refresh still valid tokens, otherwise new request to api/login will be required.

Cookie based authentication

You can also authenticate using cookie-based sessions. Before calling any other endpoints you have to obtain XSRF cookie by hitting /sanctum/csrf-cookie endpoint. In return you receive XSRF-TOKEN cookie, which content you have to attach to each request as X-XSRF-TOKEN header.

Then call /login endpoint. When your authenticated session is created, call any endpoint using X-XSRF-TOKEN header.

Multi-Factor Authorization (MFA)

User can protect its account setting up the MFA as email or one-time passwords (OTP). If mfa_enabled is set to 1 and mfa_method is set to any of email or otp values, user will have to use preferred method as second factor on login.

If mfa_method is email, API will automatically send MFA code to user's email inbox.

Most of API endpoints are secured with additional layer and cannot be properly called without this second-factor authorization done. Instead of endpoint response API will reply with message "MFA is required for this request." and HTTP code 401 Unauthorized. That means user did not successfully authorized itself with second-factor.

Multi-Factor Authorization (MFA) - Remember Session

The user has the option to remember their device, which means they won't have to enter the MFA code for 30 days. If using a Token based authentication, you need to add a header named X-MFA-Session-Token with the value {mfa_token} obtained from the /verify endpoint.

Activation codes

API endpoints for activation codes

Get activation codes

requires authentication supports: sorting

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/activation-codes?sortby=date&sortdir=asc" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/activation-codes"
);

let params = {
    "sortby": "date",
    "sortdir": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage activation codes",
    "code": "ACTIVATION_CODE:MANAGE:INSUFFICIENT_PERMISSION"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 486,
            "code": "RZAGJS",
            "created_by": 14931,
            "used_by": 14932,
            "used_at": null,
            "active": 0,
            "created_at": "2025-01-08T10:15:40.000000Z",
            "updated_at": "2025-01-08T10:15:40.000000Z"
        },
        {
            "id": 487,
            "code": "46GAJI",
            "created_by": 14933,
            "used_by": 14934,
            "used_at": null,
            "active": 0,
            "created_at": "2025-01-08T10:15:40.000000Z",
            "updated_at": "2025-01-08T10:15:40.000000Z"
        }
    ]
}

Request   

GET api/activation-codes

Query Parameters

sortby  string optional  
Sort by field (available: date). Default: date (desc).

sortdir  string optional  
Sort direction (available: asc, desc).

Get active activation codes

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/activation-codes/active" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/activation-codes/active"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage activation codes",
    "code": "ACTIVATION_CODE:MANAGE:INSUFFICIENT_PERMISSION"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 488,
            "code": "P0O4XG",
            "created_by": 14935,
            "used_by": 14936,
            "used_at": null,
            "active": 0,
            "created_at": "2025-01-08T10:15:40.000000Z",
            "updated_at": "2025-01-08T10:15:40.000000Z"
        },
        {
            "id": 489,
            "code": "GG9AO5",
            "created_by": 14937,
            "used_by": 14938,
            "used_at": null,
            "active": 1,
            "created_at": "2025-01-08T10:15:40.000000Z",
            "updated_at": "2025-01-08T10:15:40.000000Z"
        }
    ]
}

Request   

GET api/activation-codes/active

Create activation code

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/activation-codes" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/activation-codes"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage activation codes",
    "code": "ACTIVATION_CODE:MANAGE:INSUFFICIENT_PERMISSION"
}

Example response (201):

{
    "id": 490,
    "code": "VWQUUI",
    "created_by": 14939,
    "used_by": 14940,
    "used_at": null,
    "active": 1,
    "created_at": "2025-01-08T10:15:41.000000Z",
    "updated_at": "2025-01-08T10:15:41.000000Z"
}

Request   

POST api/activation-codes

Deactivate activation code

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/activation-codes/18" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/activation-codes/18"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage activation codes",
    "code": "ACTIVATION_CODE:MANAGE:INSUFFICIENT_PERMISSION"
}

Example response (404, Activation code not found):

{
    "message": "Activation code not found"
}

Example response (403, Activation code is not active):

{
    "message": "Cannot deactivate: code is not active",
    "code": "ACTIVATION_CODE:DEACTIVATE:CODE_NOT_ACTIVE"
}

Example response (202):

{
    "id": 491,
    "code": "0AB6VY",
    "created_by": 14941,
    "used_by": 14942,
    "used_at": null,
    "active": 1,
    "created_at": "2025-01-08T10:15:41.000000Z",
    "updated_at": "2025-01-08T10:15:41.000000Z"
}

Request   

DELETE api/activation-codes/{codeId}

URL Parameters

codeId  integer  
Activation Code ID

Authentication

Login user

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/login" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"email":"test@example.com","password":"secretpassword"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/login"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "test@example.com",
    "password": "secretpassword"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (422, Invalid credentials):

{
    "message": "The given data was invalid.",
    "errors": {
        "email": [
            "Given credentials not found"
        ]
    }
}

Example response (403, Too many attempts):

{
    "message": "Login: too many attempts"
}

Example response (200):

{
    "access_token": "7|x7de9EgE0xiBNLgHU91DHvhj85HVgTG1bekCssIA",
    "expires": "2021-10-25 17:05:25"
}

Request   

POST api/login

Body Parameters

email  string  
User email. The value must be a valid email address.

password  string  
User password.

Register user

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/register" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"region":"a","name":"Tom Smith","email":"name@domain.com","password":"Test123!","phone":"(564) 639-8537","phone_country":"US","language":"perferendis","clinic_name":"Lubowitz and Sons","clinic_location":"North Rustyton","address1":"2813 Runolfsson Park","address2":"East Clotildebury, DC 08792-3173","mfa_enabled":true,"mfa_method":"email","activation_code":"1A2B3C"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/register"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "region": "a",
    "name": "Tom Smith",
    "email": "name@domain.com",
    "password": "Test123!",
    "phone": "(564) 639-8537",
    "phone_country": "US",
    "language": "perferendis",
    "clinic_name": "Lubowitz and Sons",
    "clinic_location": "North Rustyton",
    "address1": "2813 Runolfsson Park",
    "address2": "East Clotildebury, DC 08792-3173",
    "mfa_enabled": true,
    "mfa_method": "email",
    "activation_code": "1A2B3C"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Too many attempts):

{
    "message": "Register: too many attempts"
}

Example response (403, E-mail in use (in another region)):

{
    "message": "E-mail address already in use (in another region)",
    "code": "AUTH:REGISTER:EMAIL_IN_USE"
}

Example response (403, Activation code is incorrect):

{
    "message": "Activation code is incorrect",
    "code": "AUTH:REGISTER:INCORRECT_CODE"
}

Example response (500, Server error):

{
    "message": "Server error: user not created",
    "code": "AUTH:REGISTER:SERVER_ERROR"
}

Example response (201):

{
    "id": 14914,
    "mrn": "H4SIGP4E",
    "name": "Larry Fadel",
    "email": "1736331338jeff68@example.net",
    "language": "en",
    "phone": "361.655.8288",
    "phone_country": "KM",
    "phone_verified_at": null,
    "address1": "57113 Goodwin Drives",
    "address2": "West Stuart, WY 03356-0795",
    "postal_code": "64334",
    "city": "Bahringer-Lindgren",
    "clinic_name": "Lake Chaimport",
    "clinic_location": "7296 Charlene Summit Apt. 526\nBergstromborough, AR 75864-3881",
    "image": null,
    "mfa_enabled": 0,
    "mfa_method": null,
    "mfa_verified_to": null,
    "created_by": null,
    "active": 1,
    "notifications_timezone": null,
    "notifications_at": null,
    "created_at": "2025-01-08T10:15:38.000000Z",
    "updated_at": "2025-01-08T10:15:38.000000Z",
    "invitation_status": "accepted",
    "roles": [
        {
            "id": 4,
            "name": "ClinicAdmin"
        }
    ],
    "devices_as_clinician": []
}

Request   

POST api/register

Body Parameters

region  string  

name  string  
User name.

email  string  
User e-mail address. The value must be a valid email address.

password  string  
User password.

phone  string  
User phone number.

phone_country  string  
Phone number's country (2 characters).

language  string  

clinic_name  string optional  
Clinic name.

clinic_location  string optional  
Clinic location.

address1  string optional  
Address line 1.

address2  string optional  
Address line 2.

mfa_enabled  boolean optional  
MFA enabled.

mfa_method  string optional  
MFA method. The value must be one of email or sms.

activation_code  string  
Activation code.

Register mobile user

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/mobile/register" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"region":"nihil","name":"Tom Smith","email":"name@domain.com","password":"Test123!","language":"en","terms_accepted":"1"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/mobile/register"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "region": "nihil",
    "name": "Tom Smith",
    "email": "name@domain.com",
    "password": "Test123!",
    "language": "en",
    "terms_accepted": "1"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Too many attempts):

{
    "message": "Register: too many attempts"
}

Example response (403, E-mail in use (in another region)):

{
    "message": "E-mail address already in use (in another region)",
    "code": "AUTH:MOBILE_REGISTER:EMAIL_IN_USE"
}

Example response (500, Server error):

{
    "message": "Server error: user not created",
    "code": "AUTH:MOBILE_REGISTER:SERVER_ERROR"
}

Example response (201):

{
    "id": 14915,
    "mrn": "K4MLHFEB",
    "name": "Dr. Gregory Osinski PhD",
    "email": "1736331338khaag@example.org",
    "language": "en",
    "phone": "+1-478-386-0110",
    "phone_country": "DK",
    "phone_verified_at": null,
    "address1": "65059 Arvilla Valleys Apt. 530",
    "address2": "Roweburgh, DC 62586-4930",
    "postal_code": "07080-7637",
    "city": "Maggio, Bogan and Franecki",
    "clinic_name": "West Maryjane",
    "clinic_location": "569 Betsy Stream\nWest Joanieview, CT 30186-9919",
    "image": null,
    "mfa_enabled": 0,
    "mfa_method": null,
    "mfa_verified_to": null,
    "created_by": null,
    "active": 1,
    "notifications_timezone": null,
    "notifications_at": null,
    "created_at": "2025-01-08T10:15:38.000000Z",
    "updated_at": "2025-01-08T10:15:38.000000Z",
    "invitation_status": "accepted",
    "roles": [
        {
            "id": 4,
            "name": "ClinicAdmin"
        }
    ],
    "devices_as_clinician": []
}

Request   

POST api/mobile/register

Body Parameters

region  string  

name  string  
User name.

email  string  
User e-mail address. The value must be a valid email address.

password  string  
User password.

language  string optional  
User language.

terms_accepted  string optional  
User accepted terms. The value must be one of 1.

Request password reset

Request sending password reset email message with token that allows to change the password

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/password/reset" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"email":"test@example.com"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/password/reset"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "test@example.com"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (404, User not found):

{
    "code": "passwords.user",
    "message": "User not found"
}

Example response (400, Throttled request):

{
    "code": "passwords.throttled",
    "message": "You have requested password reset recently"
}

Example response (200):

{
    "code": "passwords.sent",
    "message": "Reset password link successfully sent"
}

Request   

POST api/password/reset

Body Parameters

email  string  
User email. The value must be a valid email address.

Verify password reset token

Check if token is valid before using it to reset password

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/password/reset/verify" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"token":"158bed12188492617e43ecfcca43f5990b3f5f0383b5083247389482b70af019","email":"test@example.com"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/password/reset/verify"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "token": "158bed12188492617e43ecfcca43f5990b3f5f0383b5083247389482b70af019",
    "email": "test@example.com"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (400, Invalid token):

{
    "message": "Invalid token"
}

Example response (200):

{
    "message": "Valid token"
}

Request   

POST api/password/reset/verify

Body Parameters

token  string  
Password reset token.

email  string  
User email. The value must be a valid email address.

Change password with token

Change user password using password reset token sent to email address

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/password/reset/change" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"token":"158bed12188492617e43ecfcca43f5990b3f5f0383b5083247389482b70af019","email":"test@example.com","password":"secretpassword"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/password/reset/change"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "token": "158bed12188492617e43ecfcca43f5990b3f5f0383b5083247389482b70af019",
    "email": "test@example.com",
    "password": "secretpassword"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (404, User not found):

{
    "code": "passwords.user",
    "message": "User not found"
}

Example response (400, Invalid token):

{
    "code": "passwords.token",
    "message": "Invalid token"
}

Example response (200):

{
    "code": "passwords.reset",
    "message": "Password changed successfully"
}

Request   

POST api/password/reset/change

Body Parameters

token  string  
Password reset token.

email  string  
User email. The value must be a valid email address.

password  string  
User new password.

Logout current device

Logout and delete current access token

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/logout" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/logout"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (202):


[]

Request   

POST api/logout

Logout everywhere

Logout and delete all access tokens owned by account

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/logout/everywhere" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/logout/everywhere"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (202):


[]

Request   

POST api/logout/everywhere

Refresh access token

Refresh the new access token from the expiring token

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/token/refresh" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/token/refresh"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (200):

{
    "access_token": "7|x7de9EgE0xiBNLgHU91DHvhj85HVgTG1bekCssIA",
    "expires": "2021-10-25 17:05:25"
}

Request   

POST api/token/refresh

Check MFA status

Check any of available MFA methods.

requires authentication

Supported methods: email, sms, otp.

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/mfa/status" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/status"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "enabled": 1,
    "method": "email",
    "phone": 1,
    "otp": 1
}

Request   

GET api/mfa/status

Response

Response Fields

enabled  integer  
Determines if user enabled MFA

method  string  
Preferred MFA method

phone  integer  
Determines if user has verified phone number and sms channel could be used

otp  integer  
Determines if user has setup OTP with authenticator application

Use recovery code

Use generated recovery code in order to access account in case when other MFA methods couldn't be used.

requires authentication

This method only checks if code is valid, implement account access scenario on your own. Sent code is removed and couldn't be used anymore. If remaining_codes counter equals zero, generate a new set.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/recovery-code" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"code":"ZZASRM6S"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/recovery-code"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "code": "ZZASRM6S"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (401, Invalid code):

{
    "message": "Invalid code"
}

Example response (200):

{
    "access_token": "7|x7de9EgE0xiBNLgHU91DHvhj85HVgTG1bekCssIA",
    "expires": "2021-10-25 17:05:25",
    "remaining_codes": 9
}

Example response (200):

{
    "access_token": "7|x7de9EgE0xiBNLgHU91DHvhj85HVgTG1bekCssIA",
    "expires": "2021-10-25 17:05:25",
    "remaining_codes": 9
}

Request   

POST api/mfa/recovery-code

Body Parameters

code  string  
Recovery code.

Send MFA code

Send multi-factor authentication code via selected channel.

requires authentication

Code is valid for 15 minutes.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/send" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"channel":"email"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/send"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "channel": "email"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (400, Channel SMS, phone number not verified):

{
    "message": "Phone number is not verified"
}

Example response (500, Channel SMS, provider problem):

{
    "message": "Code sending failed"
}

Example response (200):

{
    "message": "Code sent"
}

Request   

POST api/mfa/send

Body Parameters

channel  string  
Authentication channel. The value must be one of email or sms.

Verify MFA code

Verify multi-factor code obtained from selected channel.

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/verify" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"channel":"email","remember_mfa_session":true,"code":"445566","machine_key":"35282880-244a-4328-9435-2aaf432f3619"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/verify"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "channel": "email",
    "remember_mfa_session": true,
    "code": "445566",
    "machine_key": "35282880-244a-4328-9435-2aaf432f3619"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (401, Invalid code):

{
    "message": "Invalid code"
}

Example response (200, OK, token auth):

{
    "access_token": "7|x7de9EgE0xiBNLgHU91DHvhj85HVgTG1bekCssIA",
    "expires": "2021-10-25 17:05:25",
    "mfa_token": "fd63e55c-2a67-44b2-95b9-a771778e9971",
    "mfa_expires": "2023-04-25 21:00:00"
}

Example response (200, OK, cookie auth):

{
    "message": "OK",
    "mfa_token": "fd63e55c-2a67-44b2-95b9-a771778e9971",
    "mfa_expires": "2023-04-25 21:00:00"
}

Request   

POST api/mfa/verify

Body Parameters

channel  string  
Authentication channel. The value must be one of email or sms.

remember_mfa_session  boolean optional  
Do not require MFA code. By default, for 30 days.

code  string  
Authentication code.

machine_key  string optional  
Unique machine identifier.

Verify phone number

Verify phone number with text message

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/phone/verify" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"code":"445566"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/phone/verify"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "code": "445566"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (401, Invalid code):

{
    "message": "Invalid code"
}

Example response (200):

{
    "message": "Phone number verified"
}

Request   

POST api/mfa/phone/verify

Body Parameters

code  string  
Verification code.

Verify MFA OTP

Verify one-time password (OTP).

requires authentication

If verification is successful, new access token with additional permissions will be generated.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/otp/verify" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"code":"445566"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/otp/verify"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "code": "445566"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (401, Invalid code):

{
    "message": "Invalid code"
}

Example response (200, OK, token auth):

{
    "access_token": "7|x7de9EgE0xiBNLgHU91DHvhj85HVgTG1bekCssIA",
    "expires": "2021-10-25 17:05:25"
}

Example response (200, OK, cookie auth):

{
    "message": "OK"
}

Request   

POST api/mfa/otp/verify

Body Parameters

code  string  
One-time password from app.

Change password

Change authenticated user password

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/password/change" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"old_password":"oldpassword","new_password":"newpassword"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/password/change"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "old_password": "oldpassword",
    "new_password": "newpassword"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (422, Invalid old password):

{
    "message": "The given data was invalid.",
    "errors": {
        "old_password": [
            "Old password is incorrect"
        ]
    }
}

Example response (200):

{
    "message": "Password changed successfully"
}

Request   

POST api/password/change

Body Parameters

old_password  string  
User old password.

new_password  string  
User new password.

Set MFA status

Set MFA status and preferred method.

requires authentication

Supported methods: email, sms, otp.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/status" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"enabled":1,"method":"email"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/status"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "enabled": 1,
    "method": "email"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):

{
    "enabled": 1,
    "method": "email",
    "phone": 1,
    "otp": 1
}

Request   

POST api/mfa/status

Body Parameters

enabled  integer optional  
Use MFA after login. The value must be one of 0 or 1.

method  string optional  
Preferred MFA method. The value must be one of email, sms, or otp.

Generate recovery codes

Generate recovery codes for authenticated user and revoke old ones.

requires authentication

User could use these codes in case when couldn't use any of MFA methods (e.g. lost device with OTP app or device is not accessible right now).

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/mfa/recovery-codes" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/recovery-codes"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "recovery_codes": [
        "A3H8PF8P",
        "IZ8CGK2H",
        "DTYENLLT",
        "0RKEZFST",
        "9MPW91BS",
        "S38Z6HS6",
        "UF5ATOKP",
        "HSZXP8EL",
        "ZZASRM6S",
        "07GR4CD1"
    ]
}

Request   

GET api/mfa/recovery-codes

Setup MFA OTP

Setup multi-factor authentication with one-time passwords (OTP).

requires authentication

Use secret on your own or generate QR code with given url. Then user could scan QR code with authentication app (e.g. Microsoft Authenticator, Authy). If secret has been already generated, new secret will override existing one and revoke previous setup.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/otp/setup" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/mfa/otp/setup"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (200):

{
    "secret": "VXGJ6JMIAWWDFXYDLKO3VG3RSGTS34BGMVTGQIEHMVVMJ2JBGCSNPQZDV4B6OMDIGI4UKCVCVKVMA7EASLHZEJWW4ZNKLAUTSZYN7EA",
    "url": "otpauth:\/\/totp\/AetherDigitalTherapy?issuer=AetherDigitalTherapy&secret=VXGJ6JMIAWWDFXYDLKO3VG3RSGTS34BGMVTGQIEHMVVMJ2JBGCSNPQZDV4B6OMDIGI4UKCVCVKVMA7EASLHZEJWW4ZNKLAUTSZYN7EA",
    "recovery_codes": [
        "A3H8PF8P",
        "IZ8CGK2H",
        "DTYENLLT",
        "0RKEZFST",
        "9MPW91BS",
        "S38Z6HS6",
        "UF5ATOKP",
        "HSZXP8EL",
        "ZZASRM6S",
        "07GR4CD1"
    ]
}

Request   

POST api/mfa/otp/setup

Login user (SPA)

Authorize user and create cookie-based session.

Hit GET /sanctum/csrf-cookie endpoint to retrieve XSRF-TOKEN cookie. Then attach X-XSRF-TOKEN HTTP header to any request to authorize. See more: Laravel Sanctum documentation

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/login" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"email":"test@example.com","password":"secretpassword"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/login"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "test@example.com",
    "password": "secretpassword"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (422, Invalid credentials):

{
    "message": "The given data was invalid.",
    "errors": {
        "email": [
            "Given credentials not found"
        ]
    }
}

Example response (403, Too many attempts):

{
    "message": "Login: too many attempts"
}

Example response (200):

{
    "mrn": "OJN1OH2C",
    "name": "Della Rippin",
    "email": "1736331358althea48@example.org",
    "language": "en",
    "phone": "+19076134994",
    "phone_country": "FM",
    "address1": "587 Herzog Villages",
    "address2": "Lake Ines, FL 84363",
    "postal_code": "19346",
    "city": "Feest and Sons",
    "clinic_name": "West Carlotta",
    "clinic_location": "1997 Emerson Overpass Apt. 655\nEast Chelsey, CO 75942-9387",
    "created_by": null,
    "active": 1,
    "updated_at": "2025-01-08T10:15:58.000000Z",
    "created_at": "2025-01-08T10:15:58.000000Z",
    "id": 15129,
    "invitation_status": null,
    "roles": []
}

Request   

POST login

Body Parameters

email  string  
User email. The value must be a valid email address.

password  string  
User password.

Chat

Authorize a user

requires authentication

This method authorizes a user using Ably service. Endpoint used only by Ably SDK

Check more details on https://ably.com/docs/auth/token

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/chat/authorize-user" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/authorize-user"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

{
    "message": "Unauthenticated."
}

Request   

GET api/chat/authorize-user

List all chat rooms

requires authentication supports: pagination

This method retrieves all chat rooms. Possible extend options:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/chat/rooms?perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/rooms"
);

let params = {
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to list chat room"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 4266,
            "owner": null,
            "patient_id": null,
            "encryption_key": "f\/hk0Xa0+V1jI+QRTEwljHSAOmON9f6KJmoFAnhbHsc=",
            "name": "molestiae",
            "friendly_name": "molestiae",
            "created_at": "2025-01-08T10:15:56.000000Z",
            "deleted_at": null,
            "updated_at": "2025-01-08T10:15:56.000000Z"
        },
        {
            "id": 4267,
            "owner": null,
            "patient_id": null,
            "encryption_key": "F23MT30g8piPDDm+aVZvQJLmuVi2PB97F\/6pvZQdloA=",
            "name": "perferendis",
            "friendly_name": "perferendis",
            "created_at": "2025-01-08T10:15:56.000000Z",
            "deleted_at": null,
            "updated_at": "2025-01-08T10:15:56.000000Z"
        }
    ]
}

Request   

GET api/chat/rooms

Query Parameters

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Retrieve a chat room

requires authentication

This method retrieves a single chat room identified by roomId. Possible extend options:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/chat/room/quia" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/room/quia"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view chat room"
}

Example response (200):

{
    "id": 4268,
    "owner": null,
    "patient_id": null,
    "encryption_key": "puqrvMjlHjucorkyKmi+hmpXbzvP49Aqno8Z1DpiU9E=",
    "name": "et",
    "friendly_name": "et",
    "created_at": "2025-01-08T10:15:56.000000Z",
    "deleted_at": null,
    "updated_at": "2025-01-08T10:15:56.000000Z"
}

Request   

GET api/chat/room/{roomName}

URL Parameters

roomName  string  

Create a new chat room

requires authentication

This method creates a new chat room using the authenticated user's ID, a name for the room, and a list of participants.

The list of participants should contain the IDs of the users who will be participants in the room.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/room" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"owner":1,"name":"my-chat","patient_id":1,"participants":"[1, 2]"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/room"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "owner": 1,
    "name": "my-chat",
    "patient_id": 1,
    "participants": "[1, 2]"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create chat room"
}

Example response (201):

{
    "id": 4269,
    "owner": null,
    "patient_id": null,
    "encryption_key": "Kc8D8Px64hw1psKm7DvVa3CVdyL2SdnBwQU945utQ74=",
    "name": "exercitationem",
    "friendly_name": "exercitationem",
    "created_at": "2025-01-08T10:15:56.000000Z",
    "deleted_at": null,
    "updated_at": "2025-01-08T10:15:56.000000Z"
}

Request   

POST api/chat/room

Body Parameters

owner  string  

name  string  
Name of chat room.

patient_id  string  

participants  string[]  
Chat room participants.

Update an existing chat room

requires authentication

This method updates an existing chat room using the authenticated user's ID, a new name for the room, and a list of participants.

The list of participants should contain the IDs of the users who will be participants in the room.

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/room/voluptas" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"owner":1,"name":"my-chat","participants":"[1, 2]","participants_del":"[1, 2]"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/room/voluptas"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "owner": 1,
    "name": "my-chat",
    "participants": "[1, 2]",
    "participants_del": "[1, 2]"
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update chat room"
}

Example response (404, Chat room not found):

{
    "message": "Chat room not found"
}

Example response (202):

{
    "id": 4270,
    "owner": null,
    "patient_id": null,
    "encryption_key": "FU0IJspN0e2ni\/S+O5IXkLD8Cd6RcS712\/caR2y3\/Is=",
    "name": "est",
    "friendly_name": "est",
    "created_at": "2025-01-08T10:15:56.000000Z",
    "deleted_at": null,
    "updated_at": "2025-01-08T10:15:56.000000Z"
}

Request   

PUT api/chat/room/{id}

URL Parameters

id  string  

Body Parameters

owner  string optional  

name  string optional  
Name of chat room.

participants  string[] optional  
Chat room participants.

participants_del  string[] optional  
Chat room participants.

Chat room archives

requires authentication supports: extending models supports: pagination supports: sorting

Get archived messages for room

Possible extend options:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/chat/room/quia/archive?extend=author&perpage=20&page=1&sortby=timestamp&sortdir=asc" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/room/quia/archive"
);

let params = {
    "extend": "author",
    "perpage": "20",
    "page": "1",
    "sortby": "timestamp",
    "sortdir": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view archived messages"
}

Example response (200, Response):

{
    "paginator": {
        "total": 1,
        "count": 1,
        "perpage": 5,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": "651a8e4868d5dc27c0000cc2",
            "channel": "chat.messages.room.44.56bf7d37-4ed6-4db4-947b-d68a1066677c.communication-channel",
            "clientId": "95",
            "msgId": "b8673175-01e6-4b6d-9032-226d3df20637",
            "data": "{\"encryptedMessage\":{\"message\":\"z6z1zNihCjlEePltz+BG8g==\",\"initialVector\":\"7376fcbf0b32fbdcd5c5b62c087b7600\"},\"user\":{\"id\":95,\"name\":\"Bartosz Druga firmaa\",\"email\":\"bartosz+drugafirma@refericon.pl\",\"image\":\"https:\/\/aether-dev-bucket.s3.amazonaws.com\/users\/7T6im01PAj4cahksWHllrL7se2SQ9buquIjGGFtp.jpg\",\"permissions\":[],\"roles\":[{\"id\":2,\"name\":\"Clinician\"}]},\"msgId\":\"b8673175-01e6-4b6d-9032-226d3df20637\",\"recipients\":[{\"delivered\":true,\"msgId\":\"b8673175-01e6-4b6d-9032-226d3df20637\",\"seen\":false,\"clientId\":\"95\"},{\"delivered\":true,\"msgId\":\"b8673175-01e6-4b6d-9032-226d3df20637\",\"seen\":false,\"clientId\":\"44\"},{\"delivered\":true,\"msgId\":\"b8673175-01e6-4b6d-9032-226d3df20637\",\"seen\":false,\"clientId\":\"1250\"},{\"delivered\":true,\"msgId\":\"b8673175-01e6-4b6d-9032-226d3df20637\",\"seen\":false,\"clientId\":\"3067\"}]}",
            "name": "message",
            "recipients": [
                {
                    "delivered": true,
                    "msgId": "b8673175-01e6-4b6d-9032-226d3df20637",
                    "seen": true,
                    "clientId": "95"
                },
                {
                    "delivered": true,
                    "msgId": "b8673175-01e6-4b6d-9032-226d3df20637",
                    "seen": false,
                    "clientId": "44"
                },
                {
                    "delivered": true,
                    "msgId": "b8673175-01e6-4b6d-9032-226d3df20637",
                    "seen": false,
                    "clientId": "1250"
                },
                {
                    "delivered": true,
                    "msgId": "b8673175-01e6-4b6d-9032-226d3df20637",
                    "seen": false,
                    "clientId": "3067"
                }
            ],
            "timestamp": 1696239176715,
            "created_at": "2023-10-02 09:32:56"
        }
    ]
}

Request   

GET api/chat/room/{id}/archive

URL Parameters

id  string  

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: author).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

sortby  string optional  
Sort by field (available: timestamp).

sortdir  string optional  
Sort direction (available: asc, desc).

Unread messages

requires authentication supports: pagination

Get unread messaged for chat room.

Possible extend options:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/chat/messages/unread?room=18&perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/messages/unread"
);

let params = {
    "room": "18",
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view unread messages list"
}

Example response (200, Success):

{
    "paginator": {
        "total": 1,
        "count": 1,
        "perpage": 5,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": "651a8e4868d5dc27c0000cc2",
            "channel": "chat.messages.room.44.56bf7d37-4ed6-4db4-947b-d68a1066677c.communication-channel",
            "clientId": "95",
            "msgId": "b8673175-01e6-4b6d-9032-226d3df20637",
            "data": "{\"encryptedMessage\":{\"message\":\"z6z1zNihCjlEePltz+BG8g==\",\"initialVector\":\"7376fcbf0b32fbdcd5c5b62c087b7600\"},\"user\":{\"id\":95,\"name\":\"Bartosz Druga firmaa\",\"email\":\"bartosz+drugafirma@refericon.pl\",\"image\":\"https:\/\/aether-dev-bucket.s3.amazonaws.com\/users\/7T6im01PAj4cahksWHllrL7se2SQ9buquIjGGFtp.jpg\",\"permissions\":[],\"roles\":[{\"id\":2,\"name\":\"Clinician\"}]},\"msgId\":\"b8673175-01e6-4b6d-9032-226d3df20637\",\"recipients\":[{\"delivered\":true,\"msgId\":\"b8673175-01e6-4b6d-9032-226d3df20637\",\"seen\":false,\"clientId\":\"95\"},{\"delivered\":true,\"msgId\":\"b8673175-01e6-4b6d-9032-226d3df20637\",\"seen\":false,\"clientId\":\"44\"},{\"delivered\":true,\"msgId\":\"b8673175-01e6-4b6d-9032-226d3df20637\",\"seen\":false,\"clientId\":\"1250\"},{\"delivered\":true,\"msgId\":\"b8673175-01e6-4b6d-9032-226d3df20637\",\"seen\":false,\"clientId\":\"3067\"}]}",
            "name": "message",
            "recipients": [
                {
                    "delivered": true,
                    "msgId": "b8673175-01e6-4b6d-9032-226d3df20637",
                    "seen": true,
                    "clientId": "95"
                },
                {
                    "delivered": true,
                    "msgId": "b8673175-01e6-4b6d-9032-226d3df20637",
                    "seen": false,
                    "clientId": "44"
                },
                {
                    "delivered": true,
                    "msgId": "b8673175-01e6-4b6d-9032-226d3df20637",
                    "seen": false,
                    "clientId": "1250"
                },
                {
                    "delivered": true,
                    "msgId": "b8673175-01e6-4b6d-9032-226d3df20637",
                    "seen": false,
                    "clientId": "3067"
                }
            ],
            "timestamp": 1696239176715,
            "created_at": "2023-10-02 09:32:56"
        }
    ]
}

Request   

GET api/chat/messages/unread

Query Parameters

room  integer optional  
Filter unread messages by room. Provide single ID (room=1), array of IDs (room[]=1&room[]=2) or comma-separated list of IDs (room=1,2).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Delete chat message

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/messages/dicta" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/messages/dicta"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to delete message"
}

Example response (404, Message not found):

{
    "message": "Chat message not found"
}

Example response (202):

{
    "message": "Message deleted"
}

Request   

DELETE api/chat/messages/{msgId}

URL Parameters

msgId  string  
Message ID

Get tickets list for chat room

requires authentication supports: extending models supports: pagination supports: sorting

Possible extend options:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/chat/tickets/dolorem?status=facilis&sender=12&recipient=12&extend=sender%2C+recipient%2C+messages%2C+messages.attachments%2C+messages.sender&perpage=20&page=1&sortby=date&sortdir=asc" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/tickets/dolorem"
);

let params = {
    "status": "facilis",
    "sender": "12",
    "recipient": "12",
    "extend": "sender, recipient, messages, messages.attachments, messages.sender",
    "perpage": "20",
    "page": "1",
    "sortby": "date",
    "sortdir": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view chat room tickets"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 4453,
            "sender_id": 15115,
            "recipient_id": 15116,
            "device_id": 6027,
            "meeting_date": "2025-01-08T10:15:56.000000Z",
            "meeting_type": "online_meeting",
            "contact_email": "breanne.west@yahoo.com",
            "status": "new",
            "created_at": "2025-01-08T10:15:56.000000Z",
            "updated_at": "2025-01-08T10:15:56.000000Z",
            "sender": {
                "id": 15115,
                "mrn": "KHWKSXNV",
                "name": "Francesca Rath",
                "email": "1736331356ruecker.johanna@example.net",
                "language": "en",
                "phone": "1-804-395-7436",
                "phone_country": "BZ",
                "phone_verified_at": null,
                "address1": "596 Schoen Creek",
                "address2": "Genevieveview, SC 69177",
                "postal_code": "44241-7689",
                "city": "Rosenbaum, Doyle and Howell",
                "clinic_name": "Rathfurt",
                "clinic_location": "56483 Nels Square Suite 960\nSouth Kierachester, IA 80382-0693",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:56.000000Z",
                "updated_at": "2025-01-08T10:15:56.000000Z",
                "invitation_status": null,
                "roles": []
            },
            "recipient": {
                "id": 15116,
                "mrn": "I3KPE0WV",
                "name": "Addison Willms",
                "email": "1736331356rschmidt@example.org",
                "language": "en",
                "phone": "743-623-6555",
                "phone_country": "SJ",
                "phone_verified_at": null,
                "address1": "7727 Kassulke Parkways",
                "address2": "New Ila, LA 24885-1305",
                "postal_code": "28773",
                "city": "Bailey, Kilback and Kihn",
                "clinic_name": "North Scot",
                "clinic_location": "61049 Delmer Mills\nZulaufmouth, MS 03163-0569",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:56.000000Z",
                "updated_at": "2025-01-08T10:15:56.000000Z",
                "invitation_status": null,
                "roles": []
            },
            "messages": [
                {
                    "id": 4545,
                    "ticket_id": 4453,
                    "sender_id": 15117,
                    "title": "Prof.",
                    "content": "Et exercitationem atque qui qui possimus aut nam eum.",
                    "is_read": false,
                    "created_at": "2025-01-08T10:15:57.000000Z",
                    "updated_at": "2025-01-08T10:15:57.000000Z",
                    "attachments": [
                        {
                            "id": 6600,
                            "ticket_id": 4453,
                            "ticket_message_id": 4545,
                            "type": "application\/vnd.kde.kword",
                            "title": "Laura Mertz",
                            "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/002255%3Ftext%3Dest",
                            "created_at": "2025-01-08T10:15:57.000000Z",
                            "updated_at": "2025-01-08T10:15:57.000000Z"
                        },
                        {
                            "id": 6601,
                            "ticket_id": 4453,
                            "ticket_message_id": 4545,
                            "type": "application\/vnd.wt.stf",
                            "title": "Jaiden Bosco II",
                            "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/0077bb%3Ftext%3Dnesciunt",
                            "created_at": "2025-01-08T10:15:57.000000Z",
                            "updated_at": "2025-01-08T10:15:57.000000Z"
                        },
                        {
                            "id": 6602,
                            "ticket_id": 4453,
                            "ticket_message_id": 4545,
                            "type": "application\/vnd.trueapp",
                            "title": "Thelma Schimmel DVM",
                            "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/00aa22%3Ftext%3Domnis",
                            "created_at": "2025-01-08T10:15:57.000000Z",
                            "updated_at": "2025-01-08T10:15:57.000000Z"
                        }
                    ],
                    "sender": {
                        "id": 15117,
                        "mrn": "01OHGBFC",
                        "name": "Santina Willms",
                        "email": "1736331356carroll.alexander@example.org",
                        "language": "en",
                        "phone": "575.971.8352",
                        "phone_country": "UY",
                        "phone_verified_at": null,
                        "address1": "67339 Ratke Stravenue Suite 080",
                        "address2": "Turnermouth, NE 30724",
                        "postal_code": "12684-2981",
                        "city": "Schaden, Konopelski and Carroll",
                        "clinic_name": "Kaylinshire",
                        "clinic_location": "8196 Kling Mountains\nMcDermottville, TN 03564",
                        "image": null,
                        "mfa_enabled": 0,
                        "mfa_method": null,
                        "mfa_verified_to": null,
                        "created_by": null,
                        "active": 1,
                        "notifications_timezone": null,
                        "notifications_at": null,
                        "created_at": "2025-01-08T10:15:57.000000Z",
                        "updated_at": "2025-01-08T10:15:57.000000Z",
                        "invitation_status": null,
                        "roles": []
                    }
                }
            ]
        },
        {
            "id": 4454,
            "sender_id": 15121,
            "recipient_id": 15122,
            "device_id": 6028,
            "meeting_date": "2025-01-08T10:15:57.000000Z",
            "meeting_type": "online_meeting",
            "contact_email": "nolson@roberts.com",
            "status": "new",
            "created_at": "2025-01-08T10:15:57.000000Z",
            "updated_at": "2025-01-08T10:15:57.000000Z",
            "sender": {
                "id": 15121,
                "mrn": "EWEF5AWS",
                "name": "Marietta Hansen",
                "email": "1736331357ltorp@example.net",
                "language": "en",
                "phone": "682-237-9482",
                "phone_country": "GL",
                "phone_verified_at": null,
                "address1": "173 Maye Isle Apt. 870",
                "address2": "East Keeganbury, OK 94305-5456",
                "postal_code": "07609-7744",
                "city": "Effertz, Heaney and Welch",
                "clinic_name": "Myrnaberg",
                "clinic_location": "585 Dayton Spur\nEast Angelicahaven, TN 80284",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:57.000000Z",
                "updated_at": "2025-01-08T10:15:57.000000Z",
                "invitation_status": null,
                "roles": []
            },
            "recipient": {
                "id": 15122,
                "mrn": "09CS9HVM",
                "name": "Ward Torphy",
                "email": "1736331357fernando66@example.com",
                "language": "en",
                "phone": "1-878-312-9045",
                "phone_country": "SR",
                "phone_verified_at": null,
                "address1": "90657 Laury Roads",
                "address2": "Roslynstad, OR 67779-3206",
                "postal_code": "03053",
                "city": "Weissnat-Kautzer",
                "clinic_name": "New Velmastad",
                "clinic_location": "7811 Purdy Plaza Suite 740\nEast Friedrichhaven, CO 29875-3648",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:57.000000Z",
                "updated_at": "2025-01-08T10:15:57.000000Z",
                "invitation_status": null,
                "roles": []
            },
            "messages": [
                {
                    "id": 4546,
                    "ticket_id": 4454,
                    "sender_id": 15123,
                    "title": "Ms.",
                    "content": "Eos aut est doloremque quis excepturi ipsam consectetur.",
                    "is_read": false,
                    "created_at": "2025-01-08T10:15:57.000000Z",
                    "updated_at": "2025-01-08T10:15:57.000000Z",
                    "attachments": [
                        {
                            "id": 6603,
                            "ticket_id": 4454,
                            "ticket_message_id": 4546,
                            "type": "model\/x3d+vrml",
                            "title": "Mrs. Filomena Reilly",
                            "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/007777%3Ftext%3Dqui",
                            "created_at": "2025-01-08T10:15:57.000000Z",
                            "updated_at": "2025-01-08T10:15:57.000000Z"
                        },
                        {
                            "id": 6604,
                            "ticket_id": 4454,
                            "ticket_message_id": 4546,
                            "type": "image\/x-freehand",
                            "title": "Madie Moore",
                            "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/0088dd%3Ftext%3Dvoluptatum",
                            "created_at": "2025-01-08T10:15:57.000000Z",
                            "updated_at": "2025-01-08T10:15:57.000000Z"
                        },
                        {
                            "id": 6605,
                            "ticket_id": 4454,
                            "ticket_message_id": 4546,
                            "type": "application\/vnd.ms-cab-compressed",
                            "title": "Myra Jacobi",
                            "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/0055bb%3Ftext%3Dquia",
                            "created_at": "2025-01-08T10:15:57.000000Z",
                            "updated_at": "2025-01-08T10:15:57.000000Z"
                        }
                    ],
                    "sender": {
                        "id": 15123,
                        "mrn": "P92CBW17",
                        "name": "Karine Heidenreich III",
                        "email": "1736331357karl11@example.com",
                        "language": "en",
                        "phone": "+1 (470) 556-6433",
                        "phone_country": "MF",
                        "phone_verified_at": null,
                        "address1": "19931 Jamey Island",
                        "address2": "Haleyville, NY 35633-9819",
                        "postal_code": "20095",
                        "city": "Kshlerin Ltd",
                        "clinic_name": "Lake Maryse",
                        "clinic_location": "853 Ritchie Island Apt. 905\nPort Deven, CA 64442-6934",
                        "image": null,
                        "mfa_enabled": 0,
                        "mfa_method": null,
                        "mfa_verified_to": null,
                        "created_by": null,
                        "active": 1,
                        "notifications_timezone": null,
                        "notifications_at": null,
                        "created_at": "2025-01-08T10:15:57.000000Z",
                        "updated_at": "2025-01-08T10:15:57.000000Z",
                        "invitation_status": null,
                        "roles": []
                    }
                }
            ]
        }
    ]
}

Request   

GET api/chat/tickets/{roomId}

URL Parameters

roomId  string  

Query Parameters

status  string optional  
Filter tickets by status (available: new,in_progress,closed,reopened).

sender  integer optional  
Filter tickets by sender.

recipient  integer optional  
Filter tickets by recipient.

extend  string optional  
Comma-separated list of relation extensions (available: sender, recipient, messages, messages.attachments, messages.sender).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

sortby  string optional  
Sort by field (available: date).

sortdir  string optional  
Sort direction (available: asc, desc).

List of available patients for chat

requires authentication supports: pagination

Possible extend options:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/chat/available-patients?perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/available-patients"
);

let params = {
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to list available patients"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 15125,
            "mrn": "RW9G44FB",
            "name": "Josie Rippin",
            "email": "1736331357margot47@example.com",
            "language": "en",
            "phone": "+1-678-607-2188",
            "phone_country": "LB",
            "phone_verified_at": null,
            "address1": "46050 Lyda Port",
            "address2": "Ferryburgh, NE 50404-0033",
            "postal_code": "31459-1036",
            "city": "Hegmann Ltd",
            "clinic_name": "Pourostown",
            "clinic_location": "57141 Lorena Knoll\nWuckertstad, NE 84153",
            "image": null,
            "mfa_enabled": 0,
            "mfa_method": null,
            "mfa_verified_to": null,
            "created_by": null,
            "active": 1,
            "notifications_timezone": null,
            "notifications_at": null,
            "created_at": "2025-01-08T10:15:57.000000Z",
            "updated_at": "2025-01-08T10:15:57.000000Z",
            "invitation_status": null,
            "roles": [
                {
                    "id": 3,
                    "name": "Amputee"
                }
            ],
            "devices": [
                {
                    "id": 6029,
                    "serial": "0f3667fe-7fe2-31d7-8302-a70496ba2118",
                    "bluetooth_id": "6cb66fa7-449f-3e47-9754-2e7fbaa78eca",
                    "model_id": null,
                    "amputee_id": 15125,
                    "firmware_version_id": null,
                    "pcb_version_id": null,
                    "active": 1,
                    "last_activity_at": "0000-00-00 00:00:00",
                    "created_at": "2025-01-08T10:15:57.000000Z",
                    "updated_at": "2025-01-08T10:15:57.000000Z"
                }
            ]
        },
        {
            "id": 15126,
            "mrn": "X7LH0IL3",
            "name": "Prof. Georgette Haley",
            "email": "1736331357pollich.ulises@example.net",
            "language": "en",
            "phone": "+14429885852",
            "phone_country": "PE",
            "phone_verified_at": null,
            "address1": "462 Gabriella Cliffs",
            "address2": "Sawaynbury, IL 04293",
            "postal_code": "50269",
            "city": "Mann-Moore",
            "clinic_name": "South Lolita",
            "clinic_location": "1744 Block Locks\nSouth Logan, PA 82919-3674",
            "image": null,
            "mfa_enabled": 0,
            "mfa_method": null,
            "mfa_verified_to": null,
            "created_by": null,
            "active": 1,
            "notifications_timezone": null,
            "notifications_at": null,
            "created_at": "2025-01-08T10:15:57.000000Z",
            "updated_at": "2025-01-08T10:15:57.000000Z",
            "invitation_status": null,
            "roles": [
                {
                    "id": 3,
                    "name": "Amputee"
                }
            ],
            "devices": [
                {
                    "id": 6030,
                    "serial": "9fb67235-ef88-3d88-8f3e-34e784dc530c",
                    "bluetooth_id": "166b6c23-49e3-3b15-840d-3750bd615264",
                    "model_id": null,
                    "amputee_id": 15126,
                    "firmware_version_id": null,
                    "pcb_version_id": null,
                    "active": 1,
                    "last_activity_at": "0000-00-00 00:00:00",
                    "created_at": "2025-01-08T10:15:57.000000Z",
                    "updated_at": "2025-01-08T10:15:57.000000Z"
                }
            ]
        }
    ]
}

Request   

GET api/chat/available-patients

Query Parameters

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

List of available participants for chat

requires authentication supports: extending models supports: pagination

Possible extend options:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/chat/room/ut/available-participants?extend=roles%2C+permissions&perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/chat/room/ut/available-participants"
);

let params = {
    "extend": "roles, permissions",
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to list available participants"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 15127,
            "mrn": "IQGYX4LL",
            "name": "Kenton Bins",
            "email": "1736331357pedro.rice@example.net",
            "language": "en",
            "phone": "1-915-409-5429",
            "phone_country": "UA",
            "phone_verified_at": null,
            "address1": "8209 Walton Course Suite 037",
            "address2": "East Margaretta, AK 72975-5451",
            "postal_code": "77697",
            "city": "Yundt, Stanton and Mraz",
            "clinic_name": "Botsfordfort",
            "clinic_location": "33792 Nicolas Divide\nFisherfort, CT 56117",
            "image": null,
            "mfa_enabled": 0,
            "mfa_method": null,
            "mfa_verified_to": null,
            "created_by": null,
            "active": 1,
            "notifications_timezone": null,
            "notifications_at": null,
            "created_at": "2025-01-08T10:15:57.000000Z",
            "updated_at": "2025-01-08T10:15:57.000000Z",
            "invitation_status": null,
            "roles": [
                {
                    "id": 3,
                    "name": "Amputee"
                }
            ],
            "permissions": []
        },
        {
            "id": 15128,
            "mrn": "BEV5TGHC",
            "name": "Raina Romaguera",
            "email": "1736331357glarkin@example.net",
            "language": "en",
            "phone": "+1-380-379-9377",
            "phone_country": "KE",
            "phone_verified_at": null,
            "address1": "19425 Howe Island Apt. 892",
            "address2": "North Porterside, NJ 24184-6082",
            "postal_code": "60388-3558",
            "city": "Luettgen-Hayes",
            "clinic_name": "North Name",
            "clinic_location": "72378 O'Reilly Burgs\nRomagueraberg, MA 73328",
            "image": null,
            "mfa_enabled": 0,
            "mfa_method": null,
            "mfa_verified_to": null,
            "created_by": null,
            "active": 1,
            "notifications_timezone": null,
            "notifications_at": null,
            "created_at": "2025-01-08T10:15:58.000000Z",
            "updated_at": "2025-01-08T10:15:58.000000Z",
            "invitation_status": null,
            "roles": [
                {
                    "id": 3,
                    "name": "Amputee"
                }
            ],
            "permissions": []
        }
    ]
}

Request   

GET api/chat/room/{id}/available-participants

URL Parameters

id  string  

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: roles, permissions).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Config Demo

List config demos

requires authentication supports: extending models supports: pagination

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/demos?accepted=1&extend=message%2C+message.ticket%2C+message.attachments&perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/demos"
);

let params = {
    "accepted": "1",
    "extend": "message, message.ticket, message.attachments",
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to access config demos"
}

Example response (422, Device not found):

{
    "message": "Device not found"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "device_id": 5946,
            "message_id": 4533,
            "config": "Explicabo debitis esse odit quae et dolor aut at.",
            "is_accepted": 0,
            "notes": "Quidem optio dignissimos praesentium aliquid et."
        },
        {
            "device_id": 5950,
            "message_id": 4535,
            "config": "Dolorem sit necessitatibus est est repudiandae consequatur animi dolore.",
            "is_accepted": 1,
            "notes": "Reprehenderit occaecati voluptas qui exercitationem."
        }
    ]
}

Request   

GET api/device/{deviceId}/config/demos

URL Parameters

deviceId  integer  
Device ID.

Query Parameters

accepted  integer optional  
Filter config demos by accepted status. If not specified, all entries will be returned. Pass -1 to get entries not accepted or rejected yet. The value must be one of -1, 0 or 1.

extend  string optional  
Comma-separated list of relation extensions (available: message, message.ticket, message.attachments).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Update config demo

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/demos/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"is_accepted":0,"notes":"Something is still not working"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/demos/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "is_accepted": 0,
    "notes": "Something is still not working"
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to access config demos"
}

Example response (422, Device not found):

{
    "message": "Device not found"
}

Example response (200):

{
    "id": 2819,
    "device_id": 5952,
    "message_id": 4536,
    "config": "Blanditiis illo et dignissimos beatae.",
    "is_accepted": 0,
    "notes": "Doloremque facere voluptates repudiandae repellendus.",
    "created_at": "2025-01-08T10:15:44.000000Z",
    "updated_at": "2025-01-08T10:15:44.000000Z",
    "device": {
        "id": 5952,
        "serial": "0426e7ec-df0c-31fb-abb3-f0062154afef",
        "bluetooth_id": "180c0268-132f-38f7-acd5-99325235cd34",
        "model_id": null,
        "amputee_id": null,
        "firmware_version_id": null,
        "pcb_version_id": null,
        "active": 1,
        "last_activity_at": "0000-00-00 00:00:00",
        "created_at": "2025-01-08T10:15:44.000000Z",
        "updated_at": "2025-01-08T10:15:44.000000Z"
    }
}

Request   

PUT api/device/{deviceId}/config/demos/{demoId}

URL Parameters

deviceId  integer  
Device ID.

demoId  integer  
Config demo ID.

Body Parameters

is_accepted  integer optional  
Determines if demo config was accepted by patient. The value must be one of 0 or 1.

notes  string optional  
Patient notes about tested config.

Config Modes

List config modes

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/device/14/config-modes" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/14/config-modes"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to list config modes"
}

Example response (422, Device not found):

{
    "message": "Device not found"
}

Example response (200):

[
    {
        "id": 14108,
        "device_id": 5981,
        "slot": null,
        "name": "Dolores saepe qui dolorem numquam quas autem maiores.",
        "active": 1,
        "created_at": "2025-01-08T10:15:45.000000Z",
        "updated_at": "2025-01-08T10:15:45.000000Z",
        "device": {
            "id": 5981,
            "serial": "e93c824d-8240-32eb-8fa8-2499c7bf9d7b",
            "bluetooth_id": "309fa76f-00da-342a-a874-f9f0c6e63a54",
            "model_id": null,
            "amputee_id": null,
            "firmware_version_id": null,
            "pcb_version_id": null,
            "active": 1,
            "last_activity_at": "0000-00-00 00:00:00",
            "created_at": "2025-01-08T10:15:45.000000Z",
            "updated_at": "2025-01-08T10:15:45.000000Z",
            "amputee": null
        }
    },
    {
        "id": 14109,
        "device_id": 5982,
        "slot": null,
        "name": "Exercitationem ratione non fugit deleniti vel.",
        "active": 1,
        "created_at": "2025-01-08T10:15:45.000000Z",
        "updated_at": "2025-01-08T10:15:45.000000Z",
        "device": {
            "id": 5982,
            "serial": "a493d6e7-8e96-3188-a1c1-f4a53c2c6000",
            "bluetooth_id": "8ae09ccb-da78-3857-abfd-92a7cb136488",
            "model_id": null,
            "amputee_id": null,
            "firmware_version_id": null,
            "pcb_version_id": null,
            "active": 1,
            "last_activity_at": "0000-00-00 00:00:00",
            "created_at": "2025-01-08T10:15:45.000000Z",
            "updated_at": "2025-01-08T10:15:45.000000Z",
            "amputee": null
        }
    }
]

Request   

GET api/device/{deviceId}/config-modes

URL Parameters

deviceId  integer  
Device ID.

Get config mode

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/device/11/config-modes/exercitationem" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/11/config-modes/exercitationem"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to list config modes"
}

Example response (422, Device not found):

{
    "message": "Device not found"
}

Example response (200):

{
    "id": 14110,
    "device_id": 5983,
    "slot": null,
    "name": "Sint laborum illo id eos quibusdam quia voluptatem.",
    "active": 1,
    "created_at": "2025-01-08T10:15:45.000000Z",
    "updated_at": "2025-01-08T10:15:45.000000Z",
    "device": {
        "id": 5983,
        "serial": "d3ad7829-767f-3feb-835e-0a4c31e0f0ce",
        "bluetooth_id": "d1d971b9-d753-34dc-b007-15068422613d",
        "model_id": null,
        "amputee_id": null,
        "firmware_version_id": null,
        "pcb_version_id": null,
        "active": 1,
        "last_activity_at": "0000-00-00 00:00:00",
        "created_at": "2025-01-08T10:15:45.000000Z",
        "updated_at": "2025-01-08T10:15:45.000000Z"
    }
}

Request   

GET api/device/{deviceId}/config-modes/{modeId}

URL Parameters

deviceId  integer  
Device ID.

modeId  string  

Create config mode

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/20/config-modes" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"slot":0,"name":"Sport mode","active":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/20/config-modes"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "slot": 0,
    "name": "Sport mode",
    "active": 1
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create config modes"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (201):

{
    "id": 14111,
    "device_id": 5984,
    "slot": null,
    "name": "Quae et alias beatae ea et sit magni.",
    "active": 0,
    "created_at": "2025-01-08T10:15:45.000000Z",
    "updated_at": "2025-01-08T10:15:45.000000Z"
}

Request   

POST api/device/{deviceId}/config-modes

URL Parameters

deviceId  integer  
Device ID.

Body Parameters

slot  integer optional  
Mode index on device The value must be one of 0, 1, or 2.

name  string  
Name of mode.

active  integer optional  
Active status. Default: 1. The value must be one of 0 or 1.

Update config mode

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config-modes/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"slot":0,"name":"Sport mode","active":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config-modes/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "slot": 0,
    "name": "Sport mode",
    "active": 1
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update config mode"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (404, Config mode not found):

{
    "message": "Config mode not found"
}

Example response (202):

{
    "id": 14112,
    "device_id": 5985,
    "slot": null,
    "name": "Ullam quos soluta vitae sint omnis.",
    "active": 1,
    "created_at": "2025-01-08T10:15:45.000000Z",
    "updated_at": "2025-01-08T10:15:45.000000Z"
}

Request   

PUT api/device/{deviceId}/config-modes/{modeId}

URL Parameters

deviceId  integer  
Device ID.

modeId  integer  
Config mode ID.

Body Parameters

slot  integer optional  
Mode index on device The value must be one of 0, 1, or 2.

name  string optional  
Name of mode.

active  integer optional  
Active status. Default: 1. The value must be one of 0 or 1.

Copy device config from template

requires authentication

Copy config template into selected config mode. Sends support ticket if patient is assigned to device, returns config instead.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config-modes/1/from-template/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config-modes/1/from-template/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update device config"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (404, Config mode not found):

{
    "message": "Config mode not found"
}

Example response (404, Config template not found):

{
    "message": "Config template not found"
}

Example response (200, Patient not assigned, returns config):

{
    "common": {
        "gripPairsConfig": [
            1,
            4,
            2,
            3,
            6,
            7,
            9,
            8
        ],
        "controlConfig": [
            0,
            1,
            0,
            0,
            0
        ],
        "emgThresholds": [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        "interval": [
            100
        ],
        "gripSequentialConfig": [
            1,
            2,
            4,
            3,
            0,
            255,
            6,
            7,
            9,
            8,
            255,
            255
        ]
    },
    "modes": [
        {
            "id": 100,
            "name": "Mode 1",
            "slot": 0,
            "config": {
                "interval": [
                    300
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        },
        {
            "id": 101,
            "name": "Mode 2",
            "slot": 1,
            "config": {
                "interval": [
                    400
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        },
        {
            "id": 102,
            "name": "Mode 3",
            "slot": 2,
            "config": {
                "interval": [
                    500
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        }
    ]
}

Example response (201):

{
    "id": 4439,
    "sender_id": 14993,
    "recipient_id": 14994,
    "device_id": 5986,
    "meeting_date": "2025-01-08T10:15:45.000000Z",
    "meeting_type": "online_meeting",
    "contact_email": "sgislason@bogisich.com",
    "status": "new",
    "created_at": "2025-01-08T10:15:45.000000Z",
    "updated_at": "2025-01-08T10:15:45.000000Z",
    "sender": {
        "id": 14993,
        "mrn": "T6YD6NDR",
        "name": "Antonietta Murphy",
        "email": "1736331345demetrius68@example.com",
        "language": "en",
        "phone": "+19377403611",
        "phone_country": "KH",
        "phone_verified_at": null,
        "address1": "495 Heathcote Rapids",
        "address2": "West Rosariotown, MT 90526-1390",
        "postal_code": "02097",
        "city": "Erdman, Gibson and Emard",
        "clinic_name": "New Wilford",
        "clinic_location": "891 Orin Station Suite 876\nGenesishaven, AZ 13131",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:45.000000Z",
        "updated_at": "2025-01-08T10:15:45.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "recipient": {
        "id": 14994,
        "mrn": "PHRK9KA3",
        "name": "Maye Lang V",
        "email": "1736331345ella.bernier@example.net",
        "language": "en",
        "phone": "1-660-721-2221",
        "phone_country": "PM",
        "phone_verified_at": null,
        "address1": "42749 Harmon View",
        "address2": "Port Shanon, MD 60613",
        "postal_code": "31669-8453",
        "city": "Hill, D'Amore and Gorczany",
        "clinic_name": "North Jettieberg",
        "clinic_location": "728 Rosalinda Crest\nSydnieshire, WI 53628-4880",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:45.000000Z",
        "updated_at": "2025-01-08T10:15:45.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "messages": [
        {
            "id": 4537,
            "ticket_id": 4439,
            "sender_id": 14995,
            "title": "Miss",
            "content": "Saepe ut voluptate nihil consequatur repellat quam fugit.",
            "is_read": false,
            "created_at": "2025-01-08T10:15:46.000000Z",
            "updated_at": "2025-01-08T10:15:46.000000Z",
            "attachments": [
                {
                    "id": 6577,
                    "ticket_id": 4439,
                    "ticket_message_id": 4537,
                    "type": "json",
                    "title": "Current config",
                    "attachment": "{\"common\":{\"fingerStrength\":[1,300],\"gripPositions\":{\"_\":0,\"0\":{\"initial\":[50,59,62,3,1],\"limit\":[95,59,64,47,23]},\"1\":{\"initial\":[32,15,3,56,20],\"limit\":[50,75,27,82,90]},\"2\":{\"initial\":[45,54,60,58,4],\"limit\":[79,92,65,67,58]},\"3\":{\"initial\":[32,72,14,89,81],\"limit\":[80,82,54,91,89]},\"4\":{\"initial\":[13,34,33,19,39],\"limit\":[95,70,89,37,63]},\"5\":{\"initial\":[83,60,2,13,38],\"limit\":[90,90,39,71,75]},\"6\":{\"initial\":[32,2,6,32,7],\"limit\":[71,63,94,86,34]},\"7\":{\"initial\":[59,62,20,13,9],\"limit\":[82,73,32,19,91]},\"8\":{\"initial\":[60,19,4,84,44],\"limit\":[84,37,82,85,75]},\"9\":{\"initial\":[22,5,91,18,3],\"limit\":[71,15,93,53,76]},\"10\":{\"initial\":[80,80,24,68,21],\"limit\":[80,92,24,73,40]},\"11\":{\"initial\":[30,14,71,20,15],\"limit\":[54,37,76,55,46]},\"12\":{\"initial\":[29,48,25,25,22],\"limit\":[92,77,33,67,78]},\"13\":{\"initial\":[32,80,77,9,89],\"limit\":[65,88,83,74,90]}},\"inputSite\":[1]},\"modes\":[{\"id\":14113,\"name\":\"Dolor vel ut quia suscipit necessitatibus hic.\",\"slot\":0,\"config\":{\"autoGrasp\":[1,100],\"coContractionTimings\":[200,100],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[20,90,40,100,10,70,100,40,70,60],\"gripPairsConfig\":[6,8,10,9,12,11,13,4],\"gripSequentialConfig\":[5,13,10,11,8,12,255,3,4,6,255,255],\"gripSwitchingMode\":[2],\"holdOpen\":[2000,2000],\"pulseTimings\":[530,400,500,50],\"softGrip\":[1],\"speedControlStrategy\":[1]}},{\"id\":14114,\"name\":\"Aut repellat distinctio optio.\",\"slot\":1,\"config\":{\"autoGrasp\":[1,100],\"coContractionTimings\":[500,300],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[30,50,30,60,30,50,100,0,100,40],\"gripPairsConfig\":[8,2,12,11,4,7,1,6],\"gripSequentialConfig\":[255,255,10,2,12,11,8,255,5,255,255,255],\"gripSwitchingMode\":[1],\"holdOpen\":[1500,2000],\"pulseTimings\":[720,950,970,410],\"softGrip\":[0],\"speedControlStrategy\":[1]}},{\"id\":14115,\"name\":\"Quia placeat non iste nobis est.\",\"slot\":2,\"config\":{\"autoGrasp\":[0,100],\"coContractionTimings\":[500,300],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[100,50,10,60,40,80,50,60,100,60],\"gripPairsConfig\":[7,10,8,4,12,11,2,1],\"gripSequentialConfig\":[255,13,12,11,255,1,2,255,255,10,3,6],\"gripSwitchingMode\":[3],\"holdOpen\":[2000,2500],\"pulseTimings\":[360,880,790,270],\"softGrip\":[1],\"speedControlStrategy\":[0]}}]}",
                    "created_at": "2025-01-08T10:15:46.000000Z",
                    "updated_at": "2025-01-08T10:15:46.000000Z"
                },
                {
                    "id": 6578,
                    "ticket_id": 4439,
                    "ticket_message_id": 4537,
                    "type": "json",
                    "title": "New config",
                    "attachment": "{\"common\":{\"fingerStrength\":[1,500],\"gripPositions\":{\"_\":0,\"0\":{\"initial\":[24,78,33,28,38],\"limit\":[68,83,84,31,60]},\"1\":{\"initial\":[2,22,30,20,41],\"limit\":[69,57,36,66,90]},\"2\":{\"initial\":[20,78,14,73,20],\"limit\":[57,78,82,86,78]},\"3\":{\"initial\":[21,32,31,59,13],\"limit\":[38,80,39,66,71]},\"4\":{\"initial\":[6,84,38,67,47],\"limit\":[15,93,69,89,48]},\"5\":{\"initial\":[8,39,66,21,60],\"limit\":[49,89,84,31,81]},\"6\":{\"initial\":[2,60,21,59,21],\"limit\":[24,74,89,75,77]},\"7\":{\"initial\":[25,16,27,77,61],\"limit\":[51,51,33,94,78]},\"8\":{\"initial\":[23,82,36,27,83],\"limit\":[55,93,51,35,85]},\"9\":{\"initial\":[52,5,43,39,66],\"limit\":[91,59,91,48,95]},\"10\":{\"initial\":[24,37,11,23,45],\"limit\":[85,57,89,25,83]},\"11\":{\"initial\":[28,71,44,69,9],\"limit\":[89,79,56,78,12]},\"12\":{\"initial\":[41,2,4,33,20],\"limit\":[81,9,41,69,26]},\"13\":{\"initial\":[33,23,75,55,29],\"limit\":[40,61,81,90,70]}},\"inputSite\":[0]},\"modes\":[{\"id\":14116,\"name\":\"Eos sapiente distinctio recusandae cumque expedita.\",\"slot\":0,\"config\":{\"autoGrasp\":[1,100],\"coContractionTimings\":[500,300],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[100,10,60,30,10,20,60,40,60,60],\"gripPairsConfig\":[13,7,12,3,5,6,10,9],\"gripSequentialConfig\":[255,255,2,255,255,5,11,255,255,9,255,3],\"gripSwitchingMode\":[3],\"holdOpen\":[2000,2000],\"pulseTimings\":[650,550,940,890],\"softGrip\":[0],\"speedControlStrategy\":[1]}},{\"id\":14117,\"name\":\"Excepturi ut sit placeat earum reiciendis.\",\"slot\":1,\"config\":{\"autoGrasp\":[1,100],\"coContractionTimings\":[400,100],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[60,40,60,80,90,70,30,40,100,0],\"gripPairsConfig\":[10,12,13,4,5,1,11,9],\"gripSequentialConfig\":[255,8,13,255,255,7,11,6,1,255,9,4],\"gripSwitchingMode\":[3],\"holdOpen\":[2000,2500],\"pulseTimings\":[120,860,790,320],\"softGrip\":[1],\"speedControlStrategy\":[0]}},{\"id\":14118,\"name\":\"Magni officiis modi nihil voluptas vitae ipsa pariatur eum.\",\"slot\":2,\"config\":{\"autoGrasp\":[1,0],\"coContractionTimings\":[500,300],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[70,40,30,10,60,100,80,30,30,50],\"gripPairsConfig\":[3,4,9,7,6,8,2,1],\"gripSequentialConfig\":[255,255,6,13,8,10,2,255,255,7,4,255],\"gripSwitchingMode\":[3],\"holdOpen\":[2000,2000],\"pulseTimings\":[630,710,590,880],\"softGrip\":[0],\"speedControlStrategy\":[1]}}]}",
                    "created_at": "2025-01-08T10:15:46.000000Z",
                    "updated_at": "2025-01-08T10:15:46.000000Z"
                }
            ],
            "config_demo": null
        }
    ]
}

Request   

POST api/device/{deviceId}/config-modes/{modeId}/from-template/{templateId}

URL Parameters

deviceId  integer  
Device ID.

modeId  integer  
Config mode ID.

templateId  integer  
Config template ID.

Config Notes

Get config entry notes list

requires authentication supports: extending models supports: pagination supports: sorting

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/1/notes?user=1&type=fugit&extend=author&perpage=20&page=1&sortby=date&sortdir=asc" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/1/notes"
);

let params = {
    "user": "1",
    "type": "fugit",
    "extend": "author",
    "perpage": "20",
    "page": "1",
    "sortby": "date",
    "sortdir": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to access config notes"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 301,
            "config_history_id": 4351,
            "user_id": 14960,
            "note": "Repudiandae perspiciatis non necessitatibus facilis dicta illo.",
            "type": "public",
            "created_at": "2025-01-08T10:15:42.000000Z",
            "updated_at": "2025-01-08T10:15:42.000000Z",
            "author": {
                "id": 14960,
                "mrn": "5FCBD5K6",
                "name": "Prof. Austin Lehner V",
                "email": "1736331342kling.cristobal@example.org",
                "language": "en",
                "phone": "+12709793263",
                "phone_country": "TL",
                "phone_verified_at": null,
                "address1": "769 Dominique Mills Apt. 422",
                "address2": "East Iliana, HI 71713",
                "postal_code": "08027-1366",
                "city": "Hane, Gusikowski and Brekke",
                "clinic_name": "Docktown",
                "clinic_location": "970 Dooley Groves Suite 959\nLennyside, NC 64274-8956",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:42.000000Z",
                "updated_at": "2025-01-08T10:15:42.000000Z",
                "invitation_status": null,
                "roles": []
            }
        },
        {
            "id": 302,
            "config_history_id": 4352,
            "user_id": 14962,
            "note": "Molestias eum quia eos ut.",
            "type": "public",
            "created_at": "2025-01-08T10:15:43.000000Z",
            "updated_at": "2025-01-08T10:15:43.000000Z",
            "author": {
                "id": 14962,
                "mrn": "8IPSV2ZQ",
                "name": "Nannie Johnson",
                "email": "1736331342oconner.kaela@example.com",
                "language": "en",
                "phone": "781-742-4326",
                "phone_country": "TZ",
                "phone_verified_at": null,
                "address1": "3634 Okuneva Shore",
                "address2": "East Mallory, AZ 10376",
                "postal_code": "31246",
                "city": "Kunze-Kub",
                "clinic_name": "East Marlonhaven",
                "clinic_location": "56219 Kulas Falls\nPollichstad, AK 27935-5291",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:43.000000Z",
                "updated_at": "2025-01-08T10:15:43.000000Z",
                "invitation_status": null,
                "roles": []
            }
        }
    ]
}

Request   

GET api/device/{deviceId}/config/{configId}/notes

URL Parameters

deviceId  integer  
Device ID.

configId  integer  
Config history entry ID.

Query Parameters

user  integer optional  
Filter notes by user.

type  string optional  
Filter notes by type (available: public and private).

extend  string optional  
Comma-separated list of relation extensions (available: author).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

sortby  string optional  
Sort by field (available: date). Default: date (desc).

sortdir  string optional  
Sort direction (available: asc, desc).

Get config entry note

requires authentication supports: extending models

Returns single config history entry note in response.

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/1/notes/1?extend=author" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/1/notes/1"
);

let params = {
    "extend": "author",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to access config notes"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (404, Config history entry not found):

{
    "message": "Config history entry not found"
}

Example response (404, Config history note not found):

{
    "message": "Config history note not found"
}

Example response (200):

{
    "id": 303,
    "config_history_id": 4353,
    "user_id": 14964,
    "note": "Veniam ea distinctio necessitatibus quas corrupti et temporibus mollitia.",
    "type": "public",
    "created_at": "2025-01-08T10:15:43.000000Z",
    "updated_at": "2025-01-08T10:15:43.000000Z",
    "author": {
        "id": 14964,
        "mrn": "K4JQ7D89",
        "name": "Myrna Kovacek",
        "email": "1736331343heffertz@example.com",
        "language": "en",
        "phone": "+1.304.772.5979",
        "phone_country": "WF",
        "phone_verified_at": null,
        "address1": "6013 Bosco Mews Suite 646",
        "address2": "Karleeland, NM 48609-9715",
        "postal_code": "43399",
        "city": "Stanton-Jast",
        "clinic_name": "Vickieshire",
        "clinic_location": "6488 Swift Flats\nAdalinechester, MN 47883",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:43.000000Z",
        "updated_at": "2025-01-08T10:15:43.000000Z",
        "invitation_status": null,
        "roles": []
    }
}

Request   

GET api/device/{deviceId}/config/{configId}/notes/{noteId}

URL Parameters

deviceId  integer  
Device ID.

configId  integer  
Config history entry ID.

noteId  integer  
Device config entry note ID.

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: author).

Create config entry note

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/1/notes" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"note":"Natus ut ratione rem impedit magni eos.","type":"public"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/1/notes"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "note": "Natus ut ratione rem impedit magni eos.",
    "type": "public"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to add config notes"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (404, Config history entry not found):

{
    "message": "Config history entry not found"
}

Example response (201):

{
    "id": 304,
    "config_history_id": 4354,
    "user_id": 14966,
    "note": "Mollitia sint ab vero quod voluptates sit rerum.",
    "type": "public",
    "created_at": "2025-01-08T10:15:43.000000Z",
    "updated_at": "2025-01-08T10:15:43.000000Z"
}

Request   

POST api/device/{deviceId}/config/{configId}/notes

URL Parameters

deviceId  integer  
Device ID.

configId  integer  
Device config entry ID.

Body Parameters

note  string optional  
Note text.

type  string optional  
Type of the note. Default: public. The value must be one of public or private.

Delete config note

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/1/notes/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/1/notes/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to delete config notes"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (404, Config history entry not found):

{
    "message": "Config history entry not found"
}

Example response (404, Config history note not found):

{
    "message": "Config history note not found"
}

Example response (202):

{
    "message": "Config history note deleted"
}

Request   

DELETE api/device/{deviceId}/config/{configId}/notes/{noteId}

URL Parameters

deviceId  integer  
Device ID.

configId  integer  
Config history entry ID.

noteId  integer  
Device config entry note ID.

Config Schema

Get config schema

requires authentication

Returns list of config schema entries for given firmware version.

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware/1/schema?filter=common" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware/1/schema"
);

let params = {
    "filter": "common",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view config schema"
}

Example response (404, Firmware version not found):

{
    "message": "Firmware version not found"
}

Example response (200):

[
    {
        "id": 1288,
        "firmware_id": 241,
        "key": "quasi",
        "is_common": 1,
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    },
    {
        "id": 1289,
        "firmware_id": 243,
        "key": "non",
        "is_common": 1,
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    }
]

Request   

GET api/versions/firmware/{firmwareId}/schema

URL Parameters

firmwareId  integer  
Firmware version ID

Query Parameters

filter  string optional  
Filter entries by type (available: modes, modes). By default all entries all returned.

Add config schema

requires authentication

Add one or many config schema entries. Each entry is one key in config. Body of this request is simple array of objects:

[
    {"key": "key_name", "is_common": 1},
    {"key": "another_name", "is_common": 0},
    ...
]

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware/8/schema" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '[{"key":"gripsPosition.0.initial","is_common":1}]'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware/8/schema"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = [
    {
        "key": "gripsPosition.0.initial",
        "is_common": 1
    }
]

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage config schema"
}

Example response (404, Firmware version not found):

{
    "message": "Firmware version not found"
}

Example response (404, Config schema entry not found):

{
    "message": "Config schema entry not found"
}

Example response (200):

[
    {
        "id": 1290,
        "firmware_id": 245,
        "key": "magnam",
        "is_common": 1,
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    },
    {
        "id": 1291,
        "firmware_id": 247,
        "key": "eum",
        "is_common": 1,
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    }
]

Request   

POST api/versions/firmware/{firmwareId}/schema

URL Parameters

firmwareId  integer  
Firmware version ID

Body Parameters

[].key  string optional  
Config key.

[].is_common  integer optional  
Information if the key belongs to common config (1) or to modes (0). Default: 1.

Delete config schema

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware/16/schema/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware/16/schema/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage config schema"
}

Example response (404, Firmware version not found):

{
    "message": "Firmware version not found"
}

Example response (202):

{
    "message": "Config schema entry deleted"
}

Request   

DELETE api/versions/firmware/{firmwareId}/schema/{schemaId}

URL Parameters

firmwareId  integer  
Firmware version ID

schemaId  integer  
Config schema ID

Config Templates Notes

Get config templates notes list

requires authentication supports: extending models supports: pagination supports: sorting

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/1/notes?user=1&extend=author&perpage=20&page=1&sortby=date&sortdir=asc" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/1/notes"
);

let params = {
    "user": "1",
    "extend": "author",
    "perpage": "20",
    "page": "1",
    "sortby": "date",
    "sortdir": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to access config templates notes"
}

Example response (404, Config template not found):

{
    "message": "Config template not found"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 129,
            "template_id": 289,
            "user_id": 14987,
            "note": "Suscipit similique dignissimos commodi vero sed occaecati.",
            "created_at": "2025-01-08T10:15:45.000000Z",
            "updated_at": "2025-01-08T10:15:45.000000Z",
            "author": {
                "id": 14987,
                "mrn": "NGE765FJ",
                "name": "Desiree Sauer",
                "email": "1736331345dangelo.kassulke@example.org",
                "language": "en",
                "phone": "+14753973916",
                "phone_country": "LS",
                "phone_verified_at": null,
                "address1": "6031 O'Keefe Village",
                "address2": "Goodwinbury, NV 20689-2685",
                "postal_code": "17605-0190",
                "city": "O'Kon-Hartmann",
                "clinic_name": "South Margareteside",
                "clinic_location": "678 Bernier Trail\nLake Eladiochester, MA 86118-2377",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:45.000000Z",
                "updated_at": "2025-01-08T10:15:45.000000Z",
                "invitation_status": null,
                "roles": []
            }
        },
        {
            "id": 130,
            "template_id": 290,
            "user_id": 14988,
            "note": "Blanditiis odio ea explicabo quis minus sapiente.",
            "created_at": "2025-01-08T10:15:45.000000Z",
            "updated_at": "2025-01-08T10:15:45.000000Z",
            "author": {
                "id": 14988,
                "mrn": "YJHZJ3E3",
                "name": "Braeden Harber",
                "email": "1736331345rosa.boyer@example.com",
                "language": "en",
                "phone": "1-352-737-1207",
                "phone_country": "SR",
                "phone_verified_at": null,
                "address1": "792 Hobart Club",
                "address2": "Port Preston, AZ 42169-9108",
                "postal_code": "73946",
                "city": "Watsica-Corwin",
                "clinic_name": "West Rafaelaville",
                "clinic_location": "62397 Schiller Brooks Suite 771\nNew Brandt, RI 54482-8133",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:45.000000Z",
                "updated_at": "2025-01-08T10:15:45.000000Z",
                "invitation_status": null,
                "roles": []
            }
        }
    ]
}

Request   

GET api/config/templates/{id}/notes

URL Parameters

id  integer  
Config template ID.

Query Parameters

user  integer optional  
Filter notes by user.

extend  string optional  
Comma-separated list of relation extensions (available: author).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

sortby  string optional  
Sort by field (available: date). Default: date (desc).

sortdir  string optional  
Sort direction (available: asc, desc).

Get config template note

requires authentication supports: extending models

Returns single config template note in response.

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/1/notes/1?extend=author" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/1/notes/1"
);

let params = {
    "extend": "author",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to access config templates notes"
}

Example response (404, Config template not found):

{
    "message": "Config template not found"
}

Example response (404, Config template note not found):

{
    "message": "Config template note not found"
}

Example response (200):

{
    "id": 131,
    "template_id": 291,
    "user_id": 14989,
    "note": "Delectus dicta voluptatum amet similique asperiores incidunt dolorum.",
    "created_at": "2025-01-08T10:15:45.000000Z",
    "updated_at": "2025-01-08T10:15:45.000000Z",
    "author": {
        "id": 14989,
        "mrn": "7P6YLXWP",
        "name": "Lisandro Stracke",
        "email": "1736331345althea69@example.net",
        "language": "en",
        "phone": "+1-574-975-5517",
        "phone_country": "TR",
        "phone_verified_at": null,
        "address1": "27421 Davion Wells Suite 137",
        "address2": "Goldnerhaven, OR 68733-5033",
        "postal_code": "38665",
        "city": "Cole PLC",
        "clinic_name": "Steuberchester",
        "clinic_location": "84877 O'Conner Isle\nLavonstad, TX 91606",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:45.000000Z",
        "updated_at": "2025-01-08T10:15:45.000000Z",
        "invitation_status": null,
        "roles": []
    }
}

Request   

GET api/config/templates/{id}/notes/{noteId}

URL Parameters

id  integer  
Config template ID.

noteId  integer  
Config template note ID.

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: author).

Create new config template note

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/1/notes" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"note":"Neque ipsum consequatur distinctio sit quisquam eius officiis cupiditate."}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/1/notes"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "note": "Neque ipsum consequatur distinctio sit quisquam eius officiis cupiditate."
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to access config templates notes"
}

Example response (404, Config template not found):

{
    "message": "Config template not found"
}

Example response (201):

{
    "id": 132,
    "template_id": 292,
    "user_id": 14990,
    "note": "Unde quo assumenda nisi rerum laboriosam eius itaque esse.",
    "created_at": "2025-01-08T10:15:45.000000Z",
    "updated_at": "2025-01-08T10:15:45.000000Z"
}

Request   

POST api/config/templates/{id}/notes

URL Parameters

id  integer  
Config template ID.

Body Parameters

note  string optional  
Note text.

Delete config template note

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/1/notes/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/1/notes/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to delete config templates notes"
}

Example response (404, Config template not found):

{
    "message": "Config template not found"
}

Example response (404, Config template note not found):

{
    "message": "Config template note not found"
}

Example response (202):

{
    "message": "Config template note deleted"
}

Request   

DELETE api/config/templates/{id}/notes/{noteId}

URL Parameters

id  integer  
Config template ID.

noteId  integer  
Config template note ID.

Config Templates

Get config templates list

requires authentication supports: extending models supports: pagination

Entries where author is present are private and owned by its author.
Entries where author is null should be considered as global templates prepared by Aether team.

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/config/templates?search=sport&author=1&scope=me&extend=author&perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates"
);

let params = {
    "search": "sport",
    "author": "1",
    "scope": "me",
    "extend": "author",
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to list config templates"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 284,
            "name": "Nostrum aut veniam magnam non.",
            "description": "Sit eligendi odio eos.",
            "author_id": 14982,
            "config": "{\"autoGrasp\":[0,0],\"coContractionTimings\":[100,100],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[20,40,40,30,20,60,30,0,10,90],\"gripPairsConfig\":[13,3,10,1,4,7,11,8],\"gripSequentialConfig\":[7,8,3,1,255,255,13,9,11,10,5,255],\"gripSwitchingMode\":[3],\"holdOpen\":[2000,2500],\"pulseTimings\":[580,670,170,570],\"softGrip\":[1],\"speedControlStrategy\":[0]}",
            "created_at": "2025-01-08T10:15:44.000000Z",
            "updated_at": "2025-01-08T10:15:44.000000Z",
            "author": {
                "id": 14982,
                "mrn": "PEOOVREM",
                "name": "Ms. Anabelle Rutherford II",
                "email": "1736331344darby69@example.org",
                "language": "en",
                "phone": "(325) 952-5328",
                "phone_country": "SB",
                "phone_verified_at": null,
                "address1": "4963 Monahan Walks Suite 775",
                "address2": "New Felicity, MD 93722",
                "postal_code": "15823-4054",
                "city": "Marks-Schmitt",
                "clinic_name": "Rociochester",
                "clinic_location": "926 Franecki Ridge Apt. 377\nFaychester, VT 90395-0282",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:44.000000Z",
                "updated_at": "2025-01-08T10:15:44.000000Z",
                "invitation_status": null,
                "roles": []
            }
        },
        {
            "id": 285,
            "name": "Neque ea repellat quia in dignissimos.",
            "description": "Quaerat quam doloribus alias laboriosam.",
            "author_id": 14983,
            "config": "{\"autoGrasp\":[0,100],\"coContractionTimings\":[500,300],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[70,0,70,40,90,40,40,20,0,20],\"gripPairsConfig\":[3,13,10,2,12,11,7,9],\"gripSequentialConfig\":[255,255,3,11,255,2,13,255,10,255,5,6],\"gripSwitchingMode\":[2],\"holdOpen\":[1500,2000],\"pulseTimings\":[950,480,670,190],\"softGrip\":[0],\"speedControlStrategy\":[0]}",
            "created_at": "2025-01-08T10:15:44.000000Z",
            "updated_at": "2025-01-08T10:15:44.000000Z",
            "author": {
                "id": 14983,
                "mrn": "7N3Y02NI",
                "name": "Elfrieda Satterfield DVM",
                "email": "1736331344fae.jast@example.org",
                "language": "en",
                "phone": "305-926-2137",
                "phone_country": "MU",
                "phone_verified_at": null,
                "address1": "5920 Hermann Turnpike",
                "address2": "Mayrafurt, HI 65570-8795",
                "postal_code": "28122-5520",
                "city": "Weimann-Schmeler",
                "clinic_name": "West Wilmer",
                "clinic_location": "94725 Deja Mountains\nFayville, UT 79521-3893",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:44.000000Z",
                "updated_at": "2025-01-08T10:15:44.000000Z",
                "invitation_status": null,
                "roles": []
            }
        }
    ]
}

Request   

GET api/config/templates

Query Parameters

search  string optional  
Filter config templates by name.

author  integer optional  
Super Admin only: Filter config templates by author.

scope  string optional  
ClinicAdmin/Clinician/ClinicianSupport only: Filter config templates by scope. The value must be one of:
- me (entries where current user is author),
- global (entries added by Aether).

extend  string optional  
Comma-separated list of relation extensions (available: author).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Get config template

requires authentication supports: extending models

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/3?extend=author" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/3"
);

let params = {
    "extend": "author",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view config template"
}

Example response (404, Config template not found):

{
    "message": "Config template not found"
}

Example response (200):

{
    "id": 286,
    "name": "Voluptate eligendi dolorem ipsam nobis dolor odit.",
    "description": "Odit eos et aut occaecati suscipit dignissimos.",
    "author_id": 14984,
    "config": "{\"autoGrasp\":[0,0],\"coContractionTimings\":[200,200],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[30,70,70,10,100,10,50,80,100,30],\"gripPairsConfig\":[13,5,3,1,9,12,6,8],\"gripSequentialConfig\":[12,2,5,7,3,13,9,6,11,255,10,255],\"gripSwitchingMode\":[2],\"holdOpen\":[2000,2500],\"pulseTimings\":[440,660,830,410],\"softGrip\":[0],\"speedControlStrategy\":[0]}",
    "created_at": "2025-01-08T10:15:44.000000Z",
    "updated_at": "2025-01-08T10:15:44.000000Z",
    "author": {
        "id": 14984,
        "mrn": "NL7BV1Z9",
        "name": "Dayna Halvorson",
        "email": "1736331344willie.gibson@example.com",
        "language": "en",
        "phone": "925.808.2328",
        "phone_country": "LB",
        "phone_verified_at": null,
        "address1": "26771 Aniyah Junction",
        "address2": "Alejandraton, SD 67591",
        "postal_code": "99694-2954",
        "city": "Simonis Inc",
        "clinic_name": "South Margieburgh",
        "clinic_location": "871 Nicolette Throughway\nWest Xanderborough, MA 13353",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:44.000000Z",
        "updated_at": "2025-01-08T10:15:44.000000Z",
        "invitation_status": null,
        "roles": []
    }
}

Request   

GET api/config/templates/{id}

URL Parameters

id  integer  
Config template ID.

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: author).

Create new config template

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Default config for Aether Zeus","description":"Description of the config template.","owner":"company","author":1,"config":"{\"param_1\": [100, 200], \"param_2\": [100, 200, 300]}"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Default config for Aether Zeus",
    "description": "Description of the config template.",
    "owner": "company",
    "author": 1,
    "config": "{\"param_1\": [100, 200], \"param_2\": [100, 200, 300]}"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create config template"
}

Example response (201):

{
    "id": 287,
    "name": "Sint laudantium recusandae fuga ipsam quis.",
    "description": "At ut quod distinctio ipsum ratione perspiciatis.",
    "author_id": 14985,
    "config": "{\"autoGrasp\":[1,100],\"coContractionTimings\":[100,100],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[10,80,10,50,20,10,50,30,80,40],\"gripPairsConfig\":[4,12,8,9,11,6,1,2],\"gripSequentialConfig\":[255,9,6,7,5,2,13,255,255,10,255,3],\"gripSwitchingMode\":[2],\"holdOpen\":[2000,2500],\"pulseTimings\":[330,50,820,770],\"softGrip\":[0],\"speedControlStrategy\":[0]}",
    "created_at": "2025-01-08T10:15:45.000000Z",
    "updated_at": "2025-01-08T10:15:45.000000Z",
    "author": {
        "id": 14985,
        "mrn": "EES6ENW3",
        "name": "Amiya Medhurst",
        "email": "1736331344estevan06@example.net",
        "language": "en",
        "phone": "(209) 984-0800",
        "phone_country": "AZ",
        "phone_verified_at": null,
        "address1": "131 Odie Brooks Apt. 982",
        "address2": "Port Tyreeside, MO 19148",
        "postal_code": "47228-5285",
        "city": "Marks Inc",
        "clinic_name": "Beierville",
        "clinic_location": "19376 Powlowski Squares\nEast D'angelo, AL 94386-0183",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:45.000000Z",
        "updated_at": "2025-01-08T10:15:45.000000Z",
        "invitation_status": null,
        "roles": []
    }
}

Request   

POST api/config/templates

Body Parameters

name  string  
Name of the config template.

description  string optional  
Description of the config template.

owner  string optional  
Mark config template owned by clinician or company. Default: me (clinician). The value must be one of me or company.

author  string optional  
Super Admin only: User ID to be the author of template.

config  string  
Full config. The value must be a valid JSON string.

Update config template

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/3" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Default config for Aether Zeus","description":"Description of the config template.","owner":"company","author":1,"config":"{\"param_1\": [100, 200], \"param_2\": [100, 200, 300]}"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/3"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Default config for Aether Zeus",
    "description": "Description of the config template.",
    "owner": "company",
    "author": 1,
    "config": "{\"param_1\": [100, 200], \"param_2\": [100, 200, 300]}"
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update config template"
}

Example response (404, Config template not found):

{
    "message": "Config template not found"
}

Example response (202):

{
    "id": 288,
    "name": "Et dolorem mollitia at eaque corrupti saepe sequi.",
    "description": "Eum cum commodi recusandae.",
    "author_id": 14986,
    "config": "{\"autoGrasp\":[1,100],\"coContractionTimings\":[500,400],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[100,20,60,60,40,20,70,80,0,90],\"gripPairsConfig\":[13,6,5,9,8,3,7,4],\"gripSequentialConfig\":[255,3,255,2,4,255,7,255,11,9,255,13],\"gripSwitchingMode\":[1],\"holdOpen\":[1500,2500],\"pulseTimings\":[280,160,980,140],\"softGrip\":[1],\"speedControlStrategy\":[0]}",
    "created_at": "2025-01-08T10:15:45.000000Z",
    "updated_at": "2025-01-08T10:15:45.000000Z",
    "author": {
        "id": 14986,
        "mrn": "TC2GM4CQ",
        "name": "Prof. Carolyne Kassulke V",
        "email": "1736331345spurdy@example.org",
        "language": "en",
        "phone": "+1-615-889-9050",
        "phone_country": "MS",
        "phone_verified_at": null,
        "address1": "32934 Avis Gateway Apt. 017",
        "address2": "South Brooks, GA 47677-6301",
        "postal_code": "77937",
        "city": "Mosciski-Kuvalis",
        "clinic_name": "North Zander",
        "clinic_location": "4208 Darby Islands\nAlifurt, OH 29281",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:45.000000Z",
        "updated_at": "2025-01-08T10:15:45.000000Z",
        "invitation_status": null,
        "roles": []
    }
}

Request   

PUT api/config/templates/{id}

URL Parameters

id  integer  
Config template ID.

Body Parameters

name  string optional  
Name of the config template.

description  string optional  
Description of the config template.

owner  string optional  
Mark config template owned by clinician or company. Default: me (clinician). The value must be one of me or company.

author  string optional  
Super Admin only: User ID to be the author of template.

config  string optional  
Full config. The value must be a valid JSON string.

Delete config template

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/3" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/config/templates/3"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to delete config template"
}

Example response (404, Config template not found):

{
    "message": "Config template not found"
}

Example response (403, Config template has existing modes):

{
    "message": "Config template has existing modes"
}

Example response (202):

{
    "message": "Config template deleted"
}

Request   

DELETE api/config/templates/{id}

URL Parameters

id  integer  
Config template ID.

Config

Get device config

requires authentication

Definitions:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config?_format=voluptas" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config"
);

let params = {
    "_format": "voluptas",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view device config"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (200, Normal/compact response):

{
    "common": {
        "gripPairsConfig": [
            1,
            4,
            2,
            3,
            6,
            7,
            9,
            8
        ],
        "controlConfig": [
            0,
            1,
            0,
            0,
            0
        ],
        "emgThresholds": [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        "interval": [
            100
        ],
        "gripSequentialConfig": [
            1,
            2,
            4,
            3,
            0,
            255,
            6,
            7,
            9,
            8,
            255,
            255
        ]
    },
    "modes": [
        {
            "id": 100,
            "name": "Mode 1",
            "slot": 0,
            "config": {
                "interval": [
                    300
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        },
        {
            "id": 101,
            "name": "Mode 2",
            "slot": 1,
            "config": {
                "interval": [
                    400
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        },
        {
            "id": 102,
            "name": "Mode 3",
            "slot": 2,
            "config": {
                "interval": [
                    500
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        }
    ]
}

Example response (200):

[
    {
        "device_id": null,
        "mode_id": null,
        "key": "perspiciatis",
        "value": "eius"
    },
    {
        "device_id": null,
        "mode_id": null,
        "key": "voluptatem",
        "value": "esse"
    }
]

Request   

GET api/device/{deviceId}/config

URL Parameters

deviceId  integer  
Device ID.

Query Parameters

_format  string optional  
Config format. Pass collection to receive config as resource collection.

Update device config

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Remote session 2022-05-30","common":"{\"gripPairsConfig\": [1, 4, 2, 3, 6, 7, 9, 8], \"controlConfig\": [0, 1, 0, 0, 0], \"gripSequentialConfig\": [1, 2, 4, 3, 0, 255, 6, 7, 9, 8, 255, 255]","modes":[{"id":1,"config":"{\"gripPairsConfig\": [1, 4, 2, 3, 6, 7, 9, 8], \"controlConfig\": [0, 1, 0, 0, 0], \"gripSequentialConfig\": [1, 2, 4, 3, 0, 255, 6, 7, 9, 8, 255, 255]"}]}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Remote session 2022-05-30",
    "common": "{\"gripPairsConfig\": [1, 4, 2, 3, 6, 7, 9, 8], \"controlConfig\": [0, 1, 0, 0, 0], \"gripSequentialConfig\": [1, 2, 4, 3, 0, 255, 6, 7, 9, 8, 255, 255]",
    "modes": [
        {
            "id": 1,
            "config": "{\"gripPairsConfig\": [1, 4, 2, 3, 6, 7, 9, 8], \"controlConfig\": [0, 1, 0, 0, 0], \"gripSequentialConfig\": [1, 2, 4, 3, 0, 255, 6, 7, 9, 8, 255, 255]"
        }
    ]
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update device config"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (422, Invalid config):


{
    "message": "Config has some problems and cannot be saved.",
    "errors": {
        "modes": {
            "mode_3": "Config mode 3 does not belong to device 12."
        },
        "values": {
            "common.inputSite": "Invalid value [\"11\"] for key inputSite - contains string values.",
            "common.gripsPositions.1.initial": "Invalid value [200,\"100\",\"100\",\"100\",\"100\"] for key gripsPositions.1.initial - contains string values.",
            "mode_1.inputSite": "Invalid value [\"11\"] for key inputSite - contains string values.",
            "mode_1.gripsPositions.0.initial": "Invalid value [\"200\",\"100\",\"100\",\"100\",\"100\"] for key gripsPositions.1.initial - contains string values.",
        }
    }
}

Example response (200):

{
    "common": {
        "gripPairsConfig": [
            1,
            4,
            2,
            3,
            6,
            7,
            9,
            8
        ],
        "controlConfig": [
            0,
            1,
            0,
            0,
            0
        ],
        "emgThresholds": [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        "interval": [
            100
        ],
        "gripSequentialConfig": [
            1,
            2,
            4,
            3,
            0,
            255,
            6,
            7,
            9,
            8,
            255,
            255
        ]
    },
    "modes": [
        {
            "id": 100,
            "name": "Mode 1",
            "slot": 0,
            "config": {
                "interval": [
                    300
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        },
        {
            "id": 101,
            "name": "Mode 2",
            "slot": 1,
            "config": {
                "interval": [
                    400
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        },
        {
            "id": 102,
            "name": "Mode 3",
            "slot": 2,
            "config": {
                "interval": [
                    500
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        }
    ]
}

Request   

POST api/device/{deviceId}/config

URL Parameters

deviceId  integer  
Device ID.

Body Parameters

name  string optional  
Config history entry name (session name).

common  string optional  
Common config as JSON string. The value must be a valid JSON string.

modes  object[] optional  

modes[].id  string optional  
Config mode ID.

modes[].config  string optional  
Config specific for mode as JSON string. The value must be a valid JSON string.

Get device config history

requires authentication supports: extending models supports: pagination supports: sorting

For amputees only restore points are returned.

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/history?restore_point=6&date_from=1642003200&date_to=1642003200&extend=author%2C+entries&perpage=20&page=1&sortby=date&sortdir=asc" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/history"
);

let params = {
    "restore_point": "6",
    "date_from": "1642003200",
    "date_to": "1642003200",
    "extend": "author, entries",
    "perpage": "20",
    "page": "1",
    "sortby": "date",
    "sortdir": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view device config"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 4347,
            "device_id": 5898,
            "index": null,
            "name": "Veniam esse error eius quia.",
            "config": "{\"common\":{\"fingerStrength\":[1,100],\"gripPositions\":{\"_\":0,\"0\":{\"initial\":[8,15,87,18,61],\"limit\":[35,75,94,92,70]},\"1\":{\"initial\":[14,15,34,13,18],\"limit\":[24,84,43,83,95]},\"2\":{\"initial\":[77,7,75,5,77],\"limit\":[84,10,88,10,93]},\"3\":{\"initial\":[74,21,31,3,33],\"limit\":[94,62,82,85,91]},\"4\":{\"initial\":[52,58,19,33,6],\"limit\":[66,65,88,63,28]},\"5\":{\"initial\":[51,45,6,44,12],\"limit\":[75,88,50,91,17]},\"6\":{\"initial\":[56,41,32,35,1],\"limit\":[65,61,50,92,12]},\"7\":{\"initial\":[25,41,28,5,35],\"limit\":[88,93,56,94,68]},\"8\":{\"initial\":[38,29,57,78,31],\"limit\":[59,70,58,90,57]},\"9\":{\"initial\":[9,6,9,8,26],\"limit\":[21,52,86,28,61]},\"10\":{\"initial\":[22,2,45,30,8],\"limit\":[32,36,48,48,77]},\"11\":{\"initial\":[9,67,15,14,33],\"limit\":[13,82,21,90,76]},\"12\":{\"initial\":[16,23,23,37,10],\"limit\":[19,93,61,94,80]},\"13\":{\"initial\":[7,38,58,22,4],\"limit\":[16,72,81,44,54]}},\"inputSite\":[1]},\"modes\":[{\"id\":14045,\"name\":\"Inventore nulla ducimus possimus eveniet earum quidem sint.\",\"slot\":0,\"config\":{\"autoGrasp\":[0,0],\"coContractionTimings\":[500,100],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[0,70,20,20,70,0,20,80,0,50],\"gripPairsConfig\":[5,13,8,3,6,9,12,2],\"gripSequentialConfig\":[255,10,5,4,13,1,3,7,12,6,8,2],\"gripSwitchingMode\":[2],\"holdOpen\":[1500,2000],\"pulseTimings\":[810,130,700,100],\"softGrip\":[1],\"speedControlStrategy\":[1]}},{\"id\":14046,\"name\":\"Perferendis eos rerum et aliquam asperiores at.\",\"slot\":1,\"config\":{\"autoGrasp\":[0,100],\"coContractionTimings\":[500,500],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[90,0,0,40,90,30,0,0,30,80],\"gripPairsConfig\":[6,10,3,9,12,7,2,11],\"gripSequentialConfig\":[3,2,9,255,255,11,4,12,255,5,255,6],\"gripSwitchingMode\":[1],\"holdOpen\":[2000,2500],\"pulseTimings\":[780,80,420,390],\"softGrip\":[0],\"speedControlStrategy\":[1]}},{\"id\":14047,\"name\":\"Consectetur ea non modi.\",\"slot\":2,\"config\":{\"autoGrasp\":[0,100],\"coContractionTimings\":[400,100],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[40,20,90,80,70,50,10,0,50,60],\"gripPairsConfig\":[3,12,11,2,6,9,13,7],\"gripSequentialConfig\":[3,255,1,4,11,10,255,2,5,255,13,9],\"gripSwitchingMode\":[2],\"holdOpen\":[2500,2500],\"pulseTimings\":[380,330,260,780],\"softGrip\":[1],\"speedControlStrategy\":[1]}}]}",
            "restore_point": 0,
            "changed_by": 14943,
            "created_at": "2025-01-08T10:15:41.000000Z",
            "updated_at": "2025-01-08T10:15:41.000000Z",
            "author": {
                "id": 14943,
                "mrn": "40HMFCPJ",
                "name": "Prof. Dandre Mitchell",
                "email": "1736331341hudson.cooper@example.net",
                "language": "en",
                "phone": "+1.337.699.7138",
                "phone_country": "PW",
                "phone_verified_at": null,
                "address1": "7600 Fisher Throughway Suite 667",
                "address2": "Roelstad, IA 98990-1783",
                "postal_code": "46124-0617",
                "city": "Leannon and Sons",
                "clinic_name": "East Remington",
                "clinic_location": "49392 Gorczany Stravenue\nHillaryborough, TN 84297",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:41.000000Z",
                "updated_at": "2025-01-08T10:15:41.000000Z",
                "invitation_status": null,
                "roles": []
            },
            "entries": []
        },
        {
            "id": 4348,
            "device_id": 5902,
            "index": null,
            "name": "Ad dignissimos quo dicta ex atque est delectus reprehenderit.",
            "config": "{\"common\":{\"fingerStrength\":[1,200],\"gripPositions\":{\"_\":0,\"0\":{\"initial\":[66,5,73,42,69],\"limit\":[66,71,80,60,74]},\"1\":{\"initial\":[23,10,49,80,44],\"limit\":[74,54,69,95,73]},\"2\":{\"initial\":[42,39,22,49,46],\"limit\":[44,95,72,78,74]},\"3\":{\"initial\":[55,4,31,11,34],\"limit\":[89,11,82,77,94]},\"4\":{\"initial\":[32,22,42,71,15],\"limit\":[87,47,79,80,39]},\"5\":{\"initial\":[10,13,31,35,53],\"limit\":[55,51,48,77,78]},\"6\":{\"initial\":[48,5,24,11,1],\"limit\":[60,34,50,14,95]},\"7\":{\"initial\":[22,54,35,15,4],\"limit\":[23,64,39,42,73]},\"8\":{\"initial\":[89,73,10,1,35],\"limit\":[95,81,73,13,79]},\"9\":{\"initial\":[6,6,40,31,23],\"limit\":[35,62,94,42,31]},\"10\":{\"initial\":[32,17,65,20,34],\"limit\":[39,64,81,56,80]},\"11\":{\"initial\":[62,31,8,47,37],\"limit\":[91,41,21,67,70]},\"12\":{\"initial\":[10,48,59,53,5],\"limit\":[39,78,95,64,71]},\"13\":{\"initial\":[16,7,24,13,29],\"limit\":[29,59,68,66,36]}},\"inputSite\":[0]},\"modes\":[{\"id\":14048,\"name\":\"Ducimus cum rerum omnis est sequi.\",\"slot\":0,\"config\":{\"autoGrasp\":[1,100],\"coContractionTimings\":[400,300],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[30,70,10,0,0,100,30,90,40,10],\"gripPairsConfig\":[10,13,1,4,5,6,8,2],\"gripSequentialConfig\":[255,6,255,255,10,4,1,255,8,13,12,11],\"gripSwitchingMode\":[1],\"holdOpen\":[1500,2500],\"pulseTimings\":[660,280,230,680],\"softGrip\":[1],\"speedControlStrategy\":[1]}},{\"id\":14049,\"name\":\"Est sit recusandae ut sint.\",\"slot\":1,\"config\":{\"autoGrasp\":[1,100],\"coContractionTimings\":[500,100],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[100,100,90,20,90,10,20,80,100,80],\"gripPairsConfig\":[9,7,13,6,11,8,10,5],\"gripSequentialConfig\":[1,10,255,3,6,9,2,255,12,13,8,11],\"gripSwitchingMode\":[1],\"holdOpen\":[2500,2500],\"pulseTimings\":[580,410,410,670],\"softGrip\":[0],\"speedControlStrategy\":[0]}},{\"id\":14050,\"name\":\"Qui non illo exercitationem quidem quasi.\",\"slot\":2,\"config\":{\"autoGrasp\":[0,0],\"coContractionTimings\":[200,200],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[30,100,30,50,100,90,70,40,30,70],\"gripPairsConfig\":[6,8,9,4,3,13,2,1],\"gripSequentialConfig\":[12,255,255,5,255,255,4,13,10,3,2,7],\"gripSwitchingMode\":[1],\"holdOpen\":[1500,2500],\"pulseTimings\":[640,260,370,620],\"softGrip\":[0],\"speedControlStrategy\":[1]}}]}",
            "restore_point": 0,
            "changed_by": 14944,
            "created_at": "2025-01-08T10:15:41.000000Z",
            "updated_at": "2025-01-08T10:15:41.000000Z",
            "author": {
                "id": 14944,
                "mrn": "A32DSV0F",
                "name": "Ms. Jana Fay Jr.",
                "email": "1736331341elvie.halvorson@example.com",
                "language": "en",
                "phone": "1-267-936-3222",
                "phone_country": "TJ",
                "phone_verified_at": null,
                "address1": "58217 Braun Coves Apt. 513",
                "address2": "Bayerborough, IN 23174-0404",
                "postal_code": "88597",
                "city": "Casper-Kemmer",
                "clinic_name": "Pacochastad",
                "clinic_location": "32813 Leora Estates Apt. 113\nHiramport, MD 26666",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:41.000000Z",
                "updated_at": "2025-01-08T10:15:41.000000Z",
                "invitation_status": null,
                "roles": []
            },
            "entries": []
        }
    ]
}

Request   

GET api/device/{deviceId}/config/history

URL Parameters

deviceId  integer  
Device ID.

Query Parameters

restore_point  integer optional  
Filter config entries by restore point status. The value must be one of 0 or 1.

date_from  integer optional  
Filter config entries from date (timestamp).

date_to  integer optional  
Filter config entries to date (timestamp).

extend  string optional  
Comma-separated list of relation extensions (available: author, entries).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

sortby  string optional  
Sort by field (available: date). Default: date (desc).

sortdir  string optional  
Sort direction (available: asc, desc).

Get device config history entry

requires authentication supports: extending models

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/history/1?extend=author%2C+entries" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/history/1"
);

let params = {
    "extend": "author, entries",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view device config"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (404, Config history entry not found):

{
    "message": "Config history entry not found"
}

Example response (202):

{
    "id": 4349,
    "device_id": 5906,
    "index": null,
    "name": "Nobis ipsam qui quia harum itaque numquam sit.",
    "config": "{\"common\":{\"fingerStrength\":[1,200],\"gripPositions\":{\"_\":0,\"0\":{\"initial\":[15,38,3,52,6],\"limit\":[61,42,17,60,93]},\"1\":{\"initial\":[10,15,3,4,32],\"limit\":[37,42,23,35,41]},\"2\":{\"initial\":[51,43,25,33,37],\"limit\":[52,76,28,68,43]},\"3\":{\"initial\":[53,36,27,83,24],\"limit\":[94,74,35,85,92]},\"4\":{\"initial\":[17,19,28,10,57],\"limit\":[47,55,72,90,87]},\"5\":{\"initial\":[11,16,30,7,52],\"limit\":[20,34,41,34,53]},\"6\":{\"initial\":[89,26,22,16,58],\"limit\":[92,86,72,46,81]},\"7\":{\"initial\":[7,38,16,13,2],\"limit\":[38,61,17,91,72]},\"8\":{\"initial\":[9,55,19,8,20],\"limit\":[15,73,30,47,79]},\"9\":{\"initial\":[67,26,19,52,52],\"limit\":[84,36,69,63,69]},\"10\":{\"initial\":[19,67,21,1,15],\"limit\":[58,82,50,62,24]},\"11\":{\"initial\":[42,32,45,60,58],\"limit\":[54,55,80,72,72]},\"12\":{\"initial\":[56,74,25,34,52],\"limit\":[76,88,90,89,62]},\"13\":{\"initial\":[6,39,4,15,60],\"limit\":[29,44,39,61,75]}},\"inputSite\":[0]},\"modes\":[{\"id\":14051,\"name\":\"Reprehenderit itaque ut sit temporibus ducimus.\",\"slot\":0,\"config\":{\"autoGrasp\":[0,0],\"coContractionTimings\":[500,300],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[50,20,40,100,90,100,40,80,90,0],\"gripPairsConfig\":[1,13,4,2,12,6,9,11],\"gripSequentialConfig\":[5,12,7,255,11,10,8,13,9,255,255,3],\"gripSwitchingMode\":[3],\"holdOpen\":[1500,2000],\"pulseTimings\":[660,610,950,890],\"softGrip\":[0],\"speedControlStrategy\":[1]}},{\"id\":14052,\"name\":\"Consequatur et distinctio minima incidunt sit.\",\"slot\":1,\"config\":{\"autoGrasp\":[1,100],\"coContractionTimings\":[200,100],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[0,80,90,10,50,10,50,30,0,60],\"gripPairsConfig\":[6,7,13,11,10,8,3,5],\"gripSequentialConfig\":[1,6,10,255,255,8,13,5,2,255,4,12],\"gripSwitchingMode\":[1],\"holdOpen\":[2500,2500],\"pulseTimings\":[400,480,120,270],\"softGrip\":[1],\"speedControlStrategy\":[0]}},{\"id\":14053,\"name\":\"Deleniti facere saepe occaecati consequatur id expedita.\",\"slot\":2,\"config\":{\"autoGrasp\":[1,0],\"coContractionTimings\":[500,300],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[90,30,40,80,40,10,10,60,40,40],\"gripPairsConfig\":[10,4,9,1,6,5,12,13],\"gripSequentialConfig\":[6,8,13,7,255,1,5,4,9,10,3,12],\"gripSwitchingMode\":[3],\"holdOpen\":[2500,2500],\"pulseTimings\":[710,730,570,580],\"softGrip\":[1],\"speedControlStrategy\":[0]}}]}",
    "restore_point": 1,
    "changed_by": 14945,
    "created_at": "2025-01-08T10:15:41.000000Z",
    "updated_at": "2025-01-08T10:15:41.000000Z"
}

Request   

GET api/device/{deviceId}/config/history/{configId}

URL Parameters

deviceId  integer  
Device ID.

configId  integer  
Config history entry ID.

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: author, entries).

Update config history

requires authentication

Returns updated config history in response.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/history/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Remote session 2022-05-30","restore_point":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/history/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Remote session 2022-05-30",
    "restore_point": 1
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update device config"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (404, Config history entry not found):

{
    "message": "Config history entry not found"
}

Example response (202):

{
    "id": 4350,
    "device_id": 5910,
    "index": null,
    "name": "Maxime nihil facilis dolore quod.",
    "config": "{\"common\":{\"fingerStrength\":[1,100],\"gripPositions\":{\"_\":0,\"0\":{\"initial\":[35,19,18,3,16],\"limit\":[88,60,61,13,68]},\"1\":{\"initial\":[62,79,35,37,8],\"limit\":[76,94,51,65,18]},\"2\":{\"initial\":[15,15,38,50,60],\"limit\":[33,20,72,70,85]},\"3\":{\"initial\":[55,19,77,31,17],\"limit\":[65,49,83,73,94]},\"4\":{\"initial\":[11,14,86,9,56],\"limit\":[39,71,89,36,69]},\"5\":{\"initial\":[39,17,48,79,2],\"limit\":[71,60,52,85,44]},\"6\":{\"initial\":[29,30,28,34,15],\"limit\":[80,38,47,82,61]},\"7\":{\"initial\":[2,15,22,40,6],\"limit\":[92,65,85,70,95]},\"8\":{\"initial\":[1,18,17,53,47],\"limit\":[3,59,78,84,69]},\"9\":{\"initial\":[1,8,50,2,42],\"limit\":[85,10,58,95,77]},\"10\":{\"initial\":[26,16,63,53,54],\"limit\":[39,83,92,84,69]},\"11\":{\"initial\":[82,4,45,87,48],\"limit\":[84,47,62,92,91]},\"12\":{\"initial\":[26,12,35,45,74],\"limit\":[43,34,42,71,80]},\"13\":{\"initial\":[33,9,54,66,26],\"limit\":[87,93,79,75,70]}},\"inputSite\":[0]},\"modes\":[{\"id\":14054,\"name\":\"Sapiente totam ad in atque vero.\",\"slot\":0,\"config\":{\"autoGrasp\":[1,0],\"coContractionTimings\":[400,400],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[60,90,90,70,90,100,10,90,40,80],\"gripPairsConfig\":[5,7,13,8,3,10,6,11],\"gripSequentialConfig\":[255,12,11,255,255,255,9,8,1,10,7,4],\"gripSwitchingMode\":[3],\"holdOpen\":[1500,2500],\"pulseTimings\":[350,720,260,670],\"softGrip\":[1],\"speedControlStrategy\":[0]}},{\"id\":14055,\"name\":\"Facilis numquam consequatur accusantium tempora.\",\"slot\":1,\"config\":{\"autoGrasp\":[1,100],\"coContractionTimings\":[200,100],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[90,70,40,60,100,10,100,10,90,70],\"gripPairsConfig\":[2,5,11,3,12,6,13,9],\"gripSequentialConfig\":[6,8,10,5,255,255,7,12,255,3,255,13],\"gripSwitchingMode\":[1],\"holdOpen\":[1500,2000],\"pulseTimings\":[750,270,670,380],\"softGrip\":[0],\"speedControlStrategy\":[1]}},{\"id\":14056,\"name\":\"Et deleniti et dolores a eveniet.\",\"slot\":2,\"config\":{\"autoGrasp\":[0,100],\"coContractionTimings\":[400,100],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[10,80,100,70,10,70,80,50,90,50],\"gripPairsConfig\":[8,3,5,9,7,13,6,10],\"gripSequentialConfig\":[255,255,12,255,13,9,11,4,10,6,3,7],\"gripSwitchingMode\":[1],\"holdOpen\":[2000,2500],\"pulseTimings\":[70,520,190,920],\"softGrip\":[1],\"speedControlStrategy\":[1]}}]}",
    "restore_point": 1,
    "changed_by": 14946,
    "created_at": "2025-01-08T10:15:41.000000Z",
    "updated_at": "2025-01-08T10:15:41.000000Z"
}

Request   

POST api/device/{deviceId}/config/history/{configId}

URL Parameters

deviceId  integer  
Device ID.

configId  integer  
Config history entry ID.

Body Parameters

name  string optional  
Config history entry name.

restore_point  integer optional  
Restore point status. The value must be one of 0 or 1.

Undo single config history change

requires authentication

Returns updated config in response.

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/history/undo/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/history/undo/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update device config"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (404, Config history entry not found):

{
    "message": "Config history entry not found"
}

Example response (200, Normal/compact response):

{
    "common": {
        "gripPairsConfig": [
            1,
            4,
            2,
            3,
            6,
            7,
            9,
            8
        ],
        "controlConfig": [
            0,
            1,
            0,
            0,
            0
        ],
        "emgThresholds": [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        "interval": [
            100
        ],
        "gripSequentialConfig": [
            1,
            2,
            4,
            3,
            0,
            255,
            6,
            7,
            9,
            8,
            255,
            255
        ]
    },
    "modes": [
        {
            "id": 100,
            "name": "Mode 1",
            "slot": 0,
            "config": {
                "interval": [
                    300
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        },
        {
            "id": 101,
            "name": "Mode 2",
            "slot": 1,
            "config": {
                "interval": [
                    400
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        },
        {
            "id": 102,
            "name": "Mode 3",
            "slot": 2,
            "config": {
                "interval": [
                    500
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        }
    ]
}

Request   

DELETE api/device/{deviceId}/config/history/undo/{configId}

URL Parameters

deviceId  integer  
Device ID.

configId  integer  
Config history entry ID.

Restore config history entry

requires authentication

Restores config from given config history entry (all changes). Sends support ticket if patient is assigned to device, returns config instead.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/restore/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/restore/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update device config"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (404, Config mode not found):

{
    "message": "Config mode not found"
}

Example response (404, Config history entry not found):

{
    "message": "Config history entry not found"
}

Example response (200, Patient not assigned, returns config):

{
    "common": {
        "gripPairsConfig": [
            1,
            4,
            2,
            3,
            6,
            7,
            9,
            8
        ],
        "controlConfig": [
            0,
            1,
            0,
            0,
            0
        ],
        "emgThresholds": [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        "interval": [
            100
        ],
        "gripSequentialConfig": [
            1,
            2,
            4,
            3,
            0,
            255,
            6,
            7,
            9,
            8,
            255,
            255
        ]
    },
    "modes": [
        {
            "id": 100,
            "name": "Mode 1",
            "slot": 0,
            "config": {
                "interval": [
                    300
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        },
        {
            "id": 101,
            "name": "Mode 2",
            "slot": 1,
            "config": {
                "interval": [
                    400
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        },
        {
            "id": 102,
            "name": "Mode 3",
            "slot": 2,
            "config": {
                "interval": [
                    500
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        }
    ]
}

Example response (201):

{
    "id": 4432,
    "sender_id": 14949,
    "recipient_id": 14950,
    "device_id": 5914,
    "meeting_date": "2025-01-08T10:15:41.000000Z",
    "meeting_type": "online_meeting",
    "contact_email": "kolby99@morissette.info",
    "status": "new",
    "created_at": "2025-01-08T10:15:42.000000Z",
    "updated_at": "2025-01-08T10:15:42.000000Z",
    "sender": {
        "id": 14949,
        "mrn": "MS3LIEKQ",
        "name": "Lilly Bogisich II",
        "email": "1736331341jewell87@example.com",
        "language": "en",
        "phone": "+1-458-827-4107",
        "phone_country": "BA",
        "phone_verified_at": null,
        "address1": "4319 Sadie Knoll",
        "address2": "South Lisa, NE 70560",
        "postal_code": "01264-9577",
        "city": "Wyman, Cummerata and Beer",
        "clinic_name": "West Modesta",
        "clinic_location": "80420 Rosalyn Ridges\nLake Pinkie, WV 95030",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:41.000000Z",
        "updated_at": "2025-01-08T10:15:41.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "recipient": {
        "id": 14950,
        "mrn": "WAH34ZS4",
        "name": "Sonia Pacocha Sr.",
        "email": "1736331341buck.lynch@example.org",
        "language": "en",
        "phone": "772-349-7851",
        "phone_country": "MX",
        "phone_verified_at": null,
        "address1": "89463 Shields Camp Suite 985",
        "address2": "East Patricia, NJ 26795",
        "postal_code": "27803-8208",
        "city": "Bashirian-Conroy",
        "clinic_name": "Lake Rossie",
        "clinic_location": "5933 Emerson Lodge\nOnieview, AZ 97545-4617",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:42.000000Z",
        "updated_at": "2025-01-08T10:15:42.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "messages": [
        {
            "id": 4530,
            "ticket_id": 4432,
            "sender_id": 14951,
            "title": "Dr.",
            "content": "Voluptatem rem pariatur necessitatibus perspiciatis itaque et.",
            "is_read": false,
            "created_at": "2025-01-08T10:15:42.000000Z",
            "updated_at": "2025-01-08T10:15:42.000000Z",
            "attachments": [
                {
                    "id": 6573,
                    "ticket_id": 4432,
                    "ticket_message_id": 4530,
                    "type": "json",
                    "title": "Current config",
                    "attachment": "{\"common\":{\"fingerStrength\":[1,400],\"gripPositions\":{\"_\":0,\"0\":{\"initial\":[2,2,20,12,11],\"limit\":[12,78,63,26,19]},\"1\":{\"initial\":[29,37,13,1,72],\"limit\":[51,86,36,91,77]},\"2\":{\"initial\":[18,20,3,43,37],\"limit\":[60,30,63,80,91]},\"3\":{\"initial\":[53,16,29,64,31],\"limit\":[64,86,67,91,88]},\"4\":{\"initial\":[31,18,33,12,10],\"limit\":[35,19,38,75,51]},\"5\":{\"initial\":[39,2,84,56,39],\"limit\":[58,34,93,66,41]},\"6\":{\"initial\":[34,76,17,37,4],\"limit\":[81,95,26,79,56]},\"7\":{\"initial\":[47,11,15,34,52],\"limit\":[92,60,19,91,60]},\"8\":{\"initial\":[32,17,20,36,24],\"limit\":[72,39,54,79,85]},\"9\":{\"initial\":[19,75,60,54,29],\"limit\":[76,79,94,78,56]},\"10\":{\"initial\":[37,7,66,19,19],\"limit\":[92,34,83,56,75]},\"11\":{\"initial\":[8,4,48,12,48],\"limit\":[88,53,53,67,49]},\"12\":{\"initial\":[13,13,22,30,31],\"limit\":[90,81,67,88,48]},\"13\":{\"initial\":[25,8,13,46,4],\"limit\":[82,56,88,74,59]}},\"inputSite\":[0]},\"modes\":[{\"id\":14057,\"name\":\"Distinctio facilis libero harum eaque.\",\"slot\":0,\"config\":{\"autoGrasp\":[1,100],\"coContractionTimings\":[500,400],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[10,30,20,20,90,10,30,90,90,90],\"gripPairsConfig\":[8,3,11,5,10,12,6,1],\"gripSequentialConfig\":[2,255,5,9,4,255,8,3,10,255,11,255],\"gripSwitchingMode\":[3],\"holdOpen\":[2500,2500],\"pulseTimings\":[70,830,330,210],\"softGrip\":[1],\"speedControlStrategy\":[0]}},{\"id\":14058,\"name\":\"Doloremque temporibus officiis qui eos ex modi ipsum nihil.\",\"slot\":1,\"config\":{\"autoGrasp\":[0,100],\"coContractionTimings\":[300,300],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[50,20,70,50,70,90,90,40,100,30],\"gripPairsConfig\":[12,1,3,8,2,4,5,7],\"gripSequentialConfig\":[5,3,8,7,12,255,255,2,6,255,1,13],\"gripSwitchingMode\":[1],\"holdOpen\":[2500,2500],\"pulseTimings\":[450,100,540,70],\"softGrip\":[1],\"speedControlStrategy\":[0]}},{\"id\":14059,\"name\":\"Fuga repudiandae iusto aut aut quasi eveniet totam.\",\"slot\":2,\"config\":{\"autoGrasp\":[1,0],\"coContractionTimings\":[400,400],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[0,10,60,100,10,0,30,0,40,90],\"gripPairsConfig\":[4,3,10,7,6,9,8,1],\"gripSequentialConfig\":[255,255,5,11,255,7,12,4,3,10,255,9],\"gripSwitchingMode\":[2],\"holdOpen\":[2000,2500],\"pulseTimings\":[330,150,400,990],\"softGrip\":[1],\"speedControlStrategy\":[0]}}]}",
                    "created_at": "2025-01-08T10:15:42.000000Z",
                    "updated_at": "2025-01-08T10:15:42.000000Z"
                },
                {
                    "id": 6574,
                    "ticket_id": 4432,
                    "ticket_message_id": 4530,
                    "type": "json",
                    "title": "New config",
                    "attachment": "{\"common\":{\"fingerStrength\":[1,400],\"gripPositions\":{\"_\":0,\"0\":{\"initial\":[29,29,72,16,47],\"limit\":[32,56,94,53,49]},\"1\":{\"initial\":[54,42,72,8,49],\"limit\":[94,58,86,94,84]},\"2\":{\"initial\":[5,65,40,27,46],\"limit\":[29,92,46,75,68]},\"3\":{\"initial\":[37,1,49,51,30],\"limit\":[62,39,85,54,38]},\"4\":{\"initial\":[28,54,35,1,5],\"limit\":[95,60,88,25,27]},\"5\":{\"initial\":[3,64,23,18,2],\"limit\":[52,79,66,29,72]},\"6\":{\"initial\":[24,28,32,19,56],\"limit\":[46,48,56,76,87]},\"7\":{\"initial\":[11,79,28,14,73],\"limit\":[52,83,88,84,90]},\"8\":{\"initial\":[37,52,48,6,17],\"limit\":[62,74,94,69,91]},\"9\":{\"initial\":[3,4,27,55,28],\"limit\":[39,61,93,74,33]},\"10\":{\"initial\":[9,9,6,58,2],\"limit\":[91,48,32,86,27]},\"11\":{\"initial\":[5,30,17,67,80],\"limit\":[59,88,62,67,92]},\"12\":{\"initial\":[53,11,39,17,14],\"limit\":[85,90,53,87,80]},\"13\":{\"initial\":[65,68,45,17,16],\"limit\":[74,92,51,82,64]}},\"inputSite\":[0]},\"modes\":[{\"id\":14060,\"name\":\"Necessitatibus sit ullam aliquam cupiditate veniam voluptatem eos.\",\"slot\":0,\"config\":{\"autoGrasp\":[0,100],\"coContractionTimings\":[500,100],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[10,20,80,60,40,10,90,70,60,50],\"gripPairsConfig\":[10,13,6,1,9,11,7,8],\"gripSequentialConfig\":[4,10,255,255,6,12,8,1,11,3,2,255],\"gripSwitchingMode\":[3],\"holdOpen\":[2000,2000],\"pulseTimings\":[290,400,280,200],\"softGrip\":[1],\"speedControlStrategy\":[0]}},{\"id\":14061,\"name\":\"Ut repudiandae culpa in deserunt quidem.\",\"slot\":1,\"config\":{\"autoGrasp\":[1,0],\"coContractionTimings\":[200,100],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[10,60,20,80,70,40,20,0,90,50],\"gripPairsConfig\":[1,6,2,3,4,9,10,12],\"gripSequentialConfig\":[255,8,13,6,9,255,4,3,11,5,255,255],\"gripSwitchingMode\":[2],\"holdOpen\":[2000,2000],\"pulseTimings\":[600,120,370,850],\"softGrip\":[1],\"speedControlStrategy\":[0]}},{\"id\":14062,\"name\":\"Asperiores cupiditate sed sit et enim sit dolor.\",\"slot\":2,\"config\":{\"autoGrasp\":[1,100],\"coContractionTimings\":[200,200],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[80,40,80,20,40,90,0,10,60,0],\"gripPairsConfig\":[7,13,10,8,12,4,3,2],\"gripSequentialConfig\":[8,2,5,1,255,3,255,7,255,4,255,12],\"gripSwitchingMode\":[2],\"holdOpen\":[1500,2500],\"pulseTimings\":[250,10,460,630],\"softGrip\":[1],\"speedControlStrategy\":[0]}}]}",
                    "created_at": "2025-01-08T10:15:42.000000Z",
                    "updated_at": "2025-01-08T10:15:42.000000Z"
                }
            ],
            "config_demo": null
        }
    ]
}

Request   

POST api/device/{deviceId}/config/restore/{configId}

URL Parameters

deviceId  integer  
Device ID.

configId  integer  
Config history entry ID.

Send test config

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/send" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"description":"Fixed problem with grips.","p2p_session":1,"common":"{\"gripPairsConfig\": [1, 4, 2, 3, 6, 7, 9, 8], \"controlConfig\": [0, 1, 0, 0, 0], \"gripSequentialConfig\": [1, 2, 4, 3, 0, 255, 6, 7, 9, 8, 255, 255]","modes":[{"id":1,"config":"{\"gripPairsConfig\": [1, 4, 2, 3, 6, 7, 9, 8], \"controlConfig\": [0, 1, 0, 0, 0], \"gripSequentialConfig\": [1, 2, 4, 3, 0, 255, 6, 7, 9, 8, 255, 255]"}]}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/config/send"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "description": "Fixed problem with grips.",
    "p2p_session": 1,
    "common": "{\"gripPairsConfig\": [1, 4, 2, 3, 6, 7, 9, 8], \"controlConfig\": [0, 1, 0, 0, 0], \"gripSequentialConfig\": [1, 2, 4, 3, 0, 255, 6, 7, 9, 8, 255, 255]",
    "modes": [
        {
            "id": 1,
            "config": "{\"gripPairsConfig\": [1, 4, 2, 3, 6, 7, 9, 8], \"controlConfig\": [0, 1, 0, 0, 0], \"gripSequentialConfig\": [1, 2, 4, 3, 0, 255, 6, 7, 9, 8, 255, 255]"
        }
    ]
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update device config"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (422, Device does not have an amputee assigned):

{
    "message": "Device does not have an amputee assigned"
}

Example response (201):

{
    "id": 4433,
    "sender_id": 14955,
    "recipient_id": 14956,
    "device_id": 5921,
    "meeting_date": "2025-01-08T10:15:42.000000Z",
    "meeting_type": "online_meeting",
    "contact_email": "cleve.connelly@gmail.com",
    "status": "new",
    "created_at": "2025-01-08T10:15:42.000000Z",
    "updated_at": "2025-01-08T10:15:42.000000Z",
    "sender": {
        "id": 14955,
        "mrn": "IUJSJ99A",
        "name": "Mr. Khalid Kuphal",
        "email": "1736331342gilda.howell@example.net",
        "language": "en",
        "phone": "(539) 229-4506",
        "phone_country": "GG",
        "phone_verified_at": null,
        "address1": "180 Annabel Street Suite 754",
        "address2": "Lake Cecileton, VA 00724",
        "postal_code": "77361-5522",
        "city": "Hoeger-Ledner",
        "clinic_name": "Markschester",
        "clinic_location": "5429 Alexis Corner Suite 090\nKatarinamouth, PA 78133",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:42.000000Z",
        "updated_at": "2025-01-08T10:15:42.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "recipient": {
        "id": 14956,
        "mrn": "DAI0ZV1R",
        "name": "Louie Murphy",
        "email": "1736331342emanuel39@example.org",
        "language": "en",
        "phone": "+14588418785",
        "phone_country": "BA",
        "phone_verified_at": null,
        "address1": "482 Kuphal Loop",
        "address2": "North Bereniceborough, NC 98083",
        "postal_code": "95498",
        "city": "Price, Ebert and Jacobs",
        "clinic_name": "Port Alphonsoville",
        "clinic_location": "930 Kunde Villages\nPagacburgh, VT 78926",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:42.000000Z",
        "updated_at": "2025-01-08T10:15:42.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "messages": [
        {
            "id": 4531,
            "ticket_id": 4433,
            "sender_id": 14957,
            "title": "Prof.",
            "content": "Sapiente enim ex quod culpa inventore nostrum.",
            "is_read": false,
            "created_at": "2025-01-08T10:15:42.000000Z",
            "updated_at": "2025-01-08T10:15:42.000000Z",
            "attachments": [
                {
                    "id": 6575,
                    "ticket_id": 4433,
                    "ticket_message_id": 4531,
                    "type": "json",
                    "title": "Current config",
                    "attachment": "{\"common\":{\"fingerStrength\":[1,300],\"gripPositions\":{\"_\":0,\"0\":{\"initial\":[23,25,30,15,17],\"limit\":[47,29,69,19,53]},\"1\":{\"initial\":[18,23,53,3,17],\"limit\":[68,31,71,78,55]},\"2\":{\"initial\":[37,23,5,29,8],\"limit\":[41,50,33,92,71]},\"3\":{\"initial\":[54,9,59,43,7],\"limit\":[67,50,71,55,21]},\"4\":{\"initial\":[5,18,70,39,30],\"limit\":[31,91,83,49,85]},\"5\":{\"initial\":[6,58,41,24,65],\"limit\":[75,68,54,72,86]},\"6\":{\"initial\":[55,45,81,33,6],\"limit\":[68,84,89,91,48]},\"7\":{\"initial\":[82,54,70,25,31],\"limit\":[83,83,90,54,34]},\"8\":{\"initial\":[6,2,13,43,10],\"limit\":[71,2,51,91,64]},\"9\":{\"initial\":[27,6,16,39,21],\"limit\":[49,43,62,41,91]},\"10\":{\"initial\":[4,4,45,74,71],\"limit\":[49,49,65,85,77]},\"11\":{\"initial\":[12,45,25,53,11],\"limit\":[23,93,80,73,79]},\"12\":{\"initial\":[25,56,82,43,45],\"limit\":[45,92,92,92,93]},\"13\":{\"initial\":[57,24,1,27,13],\"limit\":[63,88,52,90,50]}},\"inputSite\":[1]},\"modes\":[{\"id\":14063,\"name\":\"In sint et sunt.\",\"slot\":0,\"config\":{\"autoGrasp\":[1,100],\"coContractionTimings\":[500,100],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[30,60,20,30,60,60,90,80,40,40],\"gripPairsConfig\":[10,7,4,13,2,12,3,8],\"gripSequentialConfig\":[6,10,7,255,4,255,3,2,13,8,1,5],\"gripSwitchingMode\":[2],\"holdOpen\":[1500,2000],\"pulseTimings\":[390,330,50,690],\"softGrip\":[0],\"speedControlStrategy\":[0]}},{\"id\":14064,\"name\":\"Ab mollitia hic ratione non earum minus quia.\",\"slot\":1,\"config\":{\"autoGrasp\":[1,0],\"coContractionTimings\":[500,400],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[1,300],\"emgThresholds\":[60,60,50,0,70,20,70,10,60,40],\"gripPairsConfig\":[7,6,2,12,10,4,5,3],\"gripSequentialConfig\":[5,13,4,255,1,9,12,3,7,6,8,255],\"gripSwitchingMode\":[1],\"holdOpen\":[2000,2000],\"pulseTimings\":[590,50,930,40],\"softGrip\":[0],\"speedControlStrategy\":[1]}},{\"id\":14065,\"name\":\"Mollitia modi molestiae non illo possimus.\",\"slot\":2,\"config\":{\"autoGrasp\":[0,0],\"coContractionTimings\":[300,100],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[20,80,100,80,10,10,20,50,60,20],\"gripPairsConfig\":[12,13,10,8,9,11,7,4],\"gripSequentialConfig\":[255,255,2,10,255,4,9,8,6,5,13,255],\"gripSwitchingMode\":[3],\"holdOpen\":[2000,2500],\"pulseTimings\":[570,920,880,420],\"softGrip\":[0],\"speedControlStrategy\":[0]}}]}",
                    "created_at": "2025-01-08T10:15:42.000000Z",
                    "updated_at": "2025-01-08T10:15:42.000000Z"
                },
                {
                    "id": 6576,
                    "ticket_id": 4433,
                    "ticket_message_id": 4531,
                    "type": "json",
                    "title": "New config",
                    "attachment": "{\"common\":{\"fingerStrength\":[1,100],\"gripPositions\":{\"_\":0,\"0\":{\"initial\":[79,1,19,22,3],\"limit\":[94,43,61,87,15]},\"1\":{\"initial\":[5,13,51,23,65],\"limit\":[70,91,61,71,78]},\"2\":{\"initial\":[7,57,36,42,36],\"limit\":[7,61,41,74,44]},\"3\":{\"initial\":[39,44,43,11,37],\"limit\":[48,84,57,74,56]},\"4\":{\"initial\":[50,31,3,1,58],\"limit\":[57,53,86,27,78]},\"5\":{\"initial\":[59,31,58,52,11],\"limit\":[84,45,92,62,65]},\"6\":{\"initial\":[10,20,27,43,28],\"limit\":[15,38,81,47,38]},\"7\":{\"initial\":[16,11,39,19,42],\"limit\":[40,25,46,73,44]},\"8\":{\"initial\":[9,24,3,79,34],\"limit\":[65,44,83,90,68]},\"9\":{\"initial\":[40,29,27,46,9],\"limit\":[51,87,58,87,85]},\"10\":{\"initial\":[24,47,12,11,11],\"limit\":[86,65,41,72,46]},\"11\":{\"initial\":[34,2,50,81,15],\"limit\":[40,35,53,93,30]},\"12\":{\"initial\":[23,49,9,75,3],\"limit\":[43,87,51,86,76]},\"13\":{\"initial\":[41,34,45,7,2],\"limit\":[65,62,51,44,74]}},\"inputSite\":[1]},\"modes\":[{\"id\":14066,\"name\":\"Voluptatibus nihil vero ut tenetur.\",\"slot\":0,\"config\":{\"autoGrasp\":[0,0],\"coContractionTimings\":[200,200],\"controlMode\":[0],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[0,0,80,40,30,100,0,90,10,70],\"gripPairsConfig\":[3,9,4,13,7,12,6,10],\"gripSequentialConfig\":[9,6,5,11,13,3,12,255,8,4,10,1],\"gripSwitchingMode\":[1],\"holdOpen\":[1500,1500],\"pulseTimings\":[110,300,880,890],\"softGrip\":[1],\"speedControlStrategy\":[1]}},{\"id\":14067,\"name\":\"Et a fugiat voluptatum tenetur exercitationem error soluta magni.\",\"slot\":1,\"config\":{\"autoGrasp\":[1,100],\"coContractionTimings\":[300,100],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[100,10,20,30,30,50,70,100,30,50],\"gripPairsConfig\":[2,4,12,8,5,9,6,11],\"gripSequentialConfig\":[255,1,255,4,3,6,255,255,8,255,9,5],\"gripSwitchingMode\":[3],\"holdOpen\":[2000,2500],\"pulseTimings\":[350,370,920,960],\"softGrip\":[0],\"speedControlStrategy\":[1]}},{\"id\":14068,\"name\":\"Sapiente officiis molestiae odit atque.\",\"slot\":2,\"config\":{\"autoGrasp\":[0,100],\"coContractionTimings\":[400,300],\"controlMode\":[1],\"emgGains\":[100,100],\"emgSpike\":[0,300],\"emgThresholds\":[70,80,100,100,40,80,10,20,20,70],\"gripPairsConfig\":[4,11,1,10,9,5,7,3],\"gripSequentialConfig\":[2,255,12,9,7,11,4,255,5,255,3,13],\"gripSwitchingMode\":[1],\"holdOpen\":[1500,2000],\"pulseTimings\":[900,490,900,60],\"softGrip\":[1],\"speedControlStrategy\":[0]}}]}",
                    "created_at": "2025-01-08T10:15:42.000000Z",
                    "updated_at": "2025-01-08T10:15:42.000000Z"
                }
            ],
            "config_demo": null
        }
    ]
}

Request   

POST api/device/{deviceId}/config/send

URL Parameters

deviceId  integer  
Device ID.

Body Parameters

description  string optional  
Config description to add in message notification.

p2p_session  integer optional  
P2P Session ID. If config was prepared during P2P session, pass its ID, if not, pass null.

common  string optional  
Common config as JSON string. The value must be a valid JSON string.

modes  object[] optional  

modes[].id  string optional  
Config mode ID.

modes[].config  string optional  
Config specific for mode as JSON string. The value must be a valid JSON string.

Convert config

requires authentication

Convert config JSON to match given Firmware Version. Keys are moved between common config and modes.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/config/convert" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"config":"[\"velit\",\"dolore\"]","firmware":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/config/convert"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "config": "[\"velit\",\"dolore\"]",
    "firmware": 1
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to convert config"
}

Example response (404, Firmware version not found):

{
    "message": "Firmware version not found"
}

Example response (200):

{
    "common": {
        "gripPairsConfig": [
            1,
            4,
            2,
            3,
            6,
            7,
            9,
            8
        ],
        "controlConfig": [
            0,
            1,
            0,
            0,
            0
        ],
        "emgThresholds": [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0
        ],
        "interval": [
            100
        ],
        "gripSequentialConfig": [
            1,
            2,
            4,
            3,
            0,
            255,
            6,
            7,
            9,
            8,
            255,
            255
        ]
    },
    "modes": [
        {
            "id": 100,
            "name": "Mode 1",
            "slot": 0,
            "config": {
                "interval": [
                    300
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        },
        {
            "id": 101,
            "name": "Mode 2",
            "slot": 1,
            "config": {
                "interval": [
                    400
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        },
        {
            "id": 102,
            "name": "Mode 3",
            "slot": 2,
            "config": {
                "interval": [
                    500
                ],
                "fingerStrength": [
                    1,
                    100
                ],
                "autoGrasp": [
                    0,
                    100
                ],
                "emgSpike": [
                    0,
                    300
                ]
            }
        }
    ]
}

Request   

POST api/config/convert

Body Parameters

config  string  
Full config JSON. The value must be a valid JSON string.

firmware  string  
Firmware Version ID to which config should be adjusted.

Custom Grips

List custom grips templates

requires authentication supports: pagination

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/custom-grips-templates?perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/custom-grips-templates"
);

let params = {
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage custom grips templates"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 2,
            "user_id": 15085,
            "name": "bednar.jonathan",
            "initial_position": "[50, 50, 50, 50, 50]",
            "limit_position": "[900, 900, 900, 900, 900]",
            "active_fingers": "[0, 1, 1, 1, 1]",
            "created_at": "2025-01-08T10:15:54.000000Z",
            "updated_at": "2025-01-08T10:15:54.000000Z"
        },
        {
            "id": 3,
            "user_id": 15086,
            "name": "heathcote.terrence",
            "initial_position": "[50, 50, 50, 50, 50]",
            "limit_position": "[900, 900, 900, 900, 900]",
            "active_fingers": "[0, 1, 1, 1, 1]",
            "created_at": "2025-01-08T10:15:54.000000Z",
            "updated_at": "2025-01-08T10:15:54.000000Z"
        }
    ]
}

Request   

GET api/custom-grips-templates

Query Parameters

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Create custom grip template

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/custom-grips-templates" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Custom Grip Template 1","initial_position":"[50, 50, 50, 50, 50]","limit_position":"[900, 900, 900, 900, 900]","active_fingers":"[0, 1, 1, 1, 1]"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/custom-grips-templates"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Custom Grip Template 1",
    "initial_position": "[50, 50, 50, 50, 50]",
    "limit_position": "[900, 900, 900, 900, 900]",
    "active_fingers": "[0, 1, 1, 1, 1]"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage custom grips templates"
}

Example response (403, Custom grip template name in use):

{
    "message": "Custom grip template name already in use"
}

Example response (201):

{
    "id": 4,
    "user_id": 15087,
    "name": "paxton32",
    "initial_position": "[50, 50, 50, 50, 50]",
    "limit_position": "[900, 900, 900, 900, 900]",
    "active_fingers": "[0, 1, 1, 1, 1]",
    "created_at": "2025-01-08T10:15:54.000000Z",
    "updated_at": "2025-01-08T10:15:54.000000Z"
}

Request   

POST api/custom-grips-templates

Body Parameters

name  string  
Name of custom grip template.

initial_position  string  
Grip initial position. Value should be a string containing the array of values. Example: "[50, 50, 50, 50, 50]".

limit_position  string  
Grip limit position. Value should be a string containing the array of values. Example: "[900, 900, 900, 900, 900]".

active_fingers  string  
Grip active fingers. Value should be a string containing the array of values. Example: "[0, 1, 1, 1, 1]".

Delete custom grip template

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/custom-grips-templates/17" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/custom-grips-templates/17"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (404, Custom grip template not found):

{
    "message": "Custom grip template not found"
}

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage custom grips templates"
}

Example response (202):

{
    "message": "Custom grip deleted"
}

Request   

DELETE api/custom-grips-templates/{id}

URL Parameters

id  integer  
Custom Grip Template ID

List custom grips

requires authentication supports: pagination

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/device/7/custom-grips?perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/7/custom-grips"
);

let params = {
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view custom grips"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 16,
            "device_id": 6019,
            "name": "zvon",
            "opposed": 1,
            "grip_number": 7,
            "created_at": "2025-01-08T10:15:54.000000Z",
            "updated_at": "2025-01-08T10:15:54.000000Z"
        },
        {
            "id": 17,
            "device_id": 6020,
            "name": "alexandro.kuphal",
            "opposed": 1,
            "grip_number": 0,
            "created_at": "2025-01-08T10:15:54.000000Z",
            "updated_at": "2025-01-08T10:15:54.000000Z"
        }
    ]
}

Request   

GET api/device/{deviceId}/custom-grips

URL Parameters

deviceId  integer  
Device ID

Query Parameters

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Create custom grip

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/custom-grips" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Custom Grip 1","opposed":1,"grip_number":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/custom-grips"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Custom Grip 1",
    "opposed": 1,
    "grip_number": 1
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage custom grips"
}

Example response (403, Custom grip name in use):

{
    "message": "Custom grip name already in use"
}

Example response (201):

{
    "id": 18,
    "device_id": 6021,
    "name": "cummerata.terence",
    "opposed": 1,
    "grip_number": 8,
    "created_at": "2025-01-08T10:15:54.000000Z",
    "updated_at": "2025-01-08T10:15:54.000000Z"
}

Request   

POST api/device/{deviceId}/custom-grips

URL Parameters

deviceId  integer  
Device ID

Body Parameters

name  string  
Name of custom grip.

opposed  integer  
Grip opposed status. The value must be one of 0 or 1.

grip_number  integer  
Grip number (not ID).

Update custom grip

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/3/custom-grips/3" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Custom Grip 1","opposed":1,"grip_number":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/3/custom-grips/3"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Custom Grip 1",
    "opposed": 1,
    "grip_number": 1
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (404, Custom grip not found):

{
    "message": "Custom grip not found"
}

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage custom grips"
}

Example response (201):

{
    "id": 19,
    "device_id": 6022,
    "name": "arlo17",
    "opposed": 1,
    "grip_number": 14,
    "created_at": "2025-01-08T10:15:54.000000Z",
    "updated_at": "2025-01-08T10:15:54.000000Z"
}

Request   

PUT api/device/{deviceId}/custom-grips/{gripId}

URL Parameters

deviceId  integer  
Device ID

gripId  integer  
Custom Grip ID

Body Parameters

name  string optional  
Name of custom grip.

opposed  integer optional  
Grip opposed status. The value must be one of 0 or 1.

grip_number  integer optional  
Grip number (not ID).

Delete custom grip

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/5/custom-grips/13" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/5/custom-grips/13"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (404, Custom grip not found):

{
    "message": "Custom grip not found"
}

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage custom grips"
}

Example response (202):

{
    "message": "Custom grip template deleted"
}

Request   

DELETE api/device/{deviceId}/custom-grips/{gripId}

URL Parameters

deviceId  integer  
Device ID

gripId  integer  
Custom Grip ID

Device Models

Get device models list

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/devices/models?active=any" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/devices/models"
);

let params = {
    "active": "any",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to list device models"
}

Example response (200):

[
    {
        "id": 190,
        "name": "Zeus hand v1",
        "type": "arm",
        "orientation": "left",
        "active": 1,
        "created_at": "2025-01-08T10:15:39.000000Z",
        "updated_at": "2025-01-08T10:15:39.000000Z"
    },
    {
        "id": 191,
        "name": "Zeus hand v1",
        "type": "leg",
        "orientation": "right",
        "active": 1,
        "created_at": "2025-01-08T10:15:39.000000Z",
        "updated_at": "2025-01-08T10:15:39.000000Z"
    }
]

Request   

GET api/devices/models

Query Parameters

active  string optional  
Filter device models by active status (available: 0 - only inactive, 1 - only active, any - all users). Default: 1.

Create device model

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/devices/models" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Zeus hand v1","type":"hand","orientation":"right","active":true}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/devices/models"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Zeus hand v1",
    "type": "hand",
    "orientation": "right",
    "active": true
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create device model"
}

Example response (201):

{
    "id": 192,
    "name": "Zeus hand v1",
    "type": "arm",
    "orientation": "right",
    "active": 1,
    "created_at": "2025-01-08T10:15:39.000000Z",
    "updated_at": "2025-01-08T10:15:39.000000Z"
}

Request   

POST api/devices/models

Body Parameters

name  string  
Model name.

type  string optional  
Model type (e.g. hand).

orientation  string optional  
Model orientation if specified.

active  boolean optional  
Device model active status (0 - inactive, 1 - active).

Update device model

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/devices/models/17" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Zeus hand v1","type":"hand","orientation":"right","active":true}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/devices/models/17"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Zeus hand v1",
    "type": "hand",
    "orientation": "right",
    "active": true
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update device model"
}

Example response (404, Device not found):

{
    "message": "Device model not found"
}

Example response (202):

{
    "id": 193,
    "name": "Zeus hand v1",
    "type": "leg",
    "orientation": "left",
    "active": 1,
    "created_at": "2025-01-08T10:15:39.000000Z",
    "updated_at": "2025-01-08T10:15:39.000000Z"
}

Request   

PUT api/devices/models/{id}

URL Parameters

id  integer  
DeviceModel ID

Body Parameters

name  string optional  
Model name.

type  string optional  
Model type (e.g. hand).

orientation  string optional  
Model orientation if specified.

active  boolean optional  
Device model active status (0 - inactive, 1 - active).

Devices

Check serial number or bluetooth ID

Public endpoint responding with status of given device serial number or bluetooth ID. If any of these numbers can be found in database, status will be true. Otherwise, status will be false (device does not exist).

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/device/check/error" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/check/error"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "status": true
}

Request   

GET api/device/check/{serial}

URL Parameters

serial  string  
Device serial number or bluetooth ID

Get devices list

requires authentication supports: extending models supports: pagination supports: sorting

Possible extend options:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/devices?search=S3R1AL-NUM83R&active=any&amputee=1&model=1&extend=model%2C+amputee%2C+clinicians%2C+firmwareVersion%2C+pcbVersion%2C+config&perpage=20&page=1&sortby=serial%2C+amputee_name%2C+date&sortdir=asc" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/devices"
);

let params = {
    "search": "S3R1AL-NUM83R",
    "active": "any",
    "amputee": "1",
    "model": "1",
    "extend": "model, amputee, clinicians, firmwareVersion, pcbVersion, config",
    "perpage": "20",
    "page": "1",
    "sortby": "serial, amputee_name, date",
    "sortdir": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to list devices"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 5892,
            "serial": "b9eeec70-83f9-3401-9048-d8870f602a58",
            "bluetooth_id": "66dc6ed7-9a8a-3ecd-b071-162ac893188d",
            "model_id": 194,
            "amputee_id": 14928,
            "firmware_version_id": null,
            "pcb_version_id": null,
            "active": 1,
            "last_activity_at": "0000-00-00 00:00:00",
            "created_at": "2025-01-08T10:15:39.000000Z",
            "updated_at": "2025-01-08T10:15:39.000000Z",
            "model": {
                "id": 194,
                "name": "Zeus hand v1",
                "type": "leg",
                "orientation": "right",
                "active": 1,
                "created_at": "2025-01-08T10:15:39.000000Z",
                "updated_at": "2025-01-08T10:15:39.000000Z"
            },
            "amputee": {
                "id": 14928,
                "mrn": "A9WT3DME",
                "name": "Rosalinda Ruecker",
                "email": "1736331339klind@example.org",
                "language": "en",
                "phone": "201-636-0314",
                "phone_country": "PK",
                "phone_verified_at": null,
                "address1": "74998 Devin Branch Apt. 070",
                "address2": "Tyrellburgh, WY 11381-9301",
                "postal_code": "51113-3499",
                "city": "Wunsch, Hammes and Monahan",
                "clinic_name": "Toyland",
                "clinic_location": "1315 Jany Light Apt. 198\nGarnettfurt, OH 18759",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:39.000000Z",
                "updated_at": "2025-01-08T10:15:39.000000Z",
                "invitation_status": null,
                "roles": []
            }
        },
        {
            "id": 5893,
            "serial": "cf1c0251-a650-302c-a2e6-7125e9c9406c",
            "bluetooth_id": "ac6140ae-8fc3-3afe-bac3-2547df424f7f",
            "model_id": 195,
            "amputee_id": 14929,
            "firmware_version_id": null,
            "pcb_version_id": null,
            "active": 1,
            "last_activity_at": "0000-00-00 00:00:00",
            "created_at": "2025-01-08T10:15:40.000000Z",
            "updated_at": "2025-01-08T10:15:40.000000Z",
            "model": {
                "id": 195,
                "name": "Zeus hand v1",
                "type": "leg",
                "orientation": "left",
                "active": 1,
                "created_at": "2025-01-08T10:15:39.000000Z",
                "updated_at": "2025-01-08T10:15:39.000000Z"
            },
            "amputee": {
                "id": 14929,
                "mrn": "MQQQJU59",
                "name": "Prof. Ferne Champlin",
                "email": "1736331339dschneider@example.com",
                "language": "en",
                "phone": "+1.270.473.9254",
                "phone_country": "VU",
                "phone_verified_at": null,
                "address1": "42965 Owen Freeway",
                "address2": "Paucekshire, LA 42548-2847",
                "postal_code": "93518",
                "city": "Rogahn, Schulist and Schroeder",
                "clinic_name": "Dwightburgh",
                "clinic_location": "82835 Kessler Curve Apt. 682\nGerholdport, CA 53043",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:40.000000Z",
                "updated_at": "2025-01-08T10:15:40.000000Z",
                "invitation_status": null,
                "roles": []
            }
        }
    ]
}

Request   

GET api/devices

Query Parameters

search  string optional  
Filter devices by searching in: serial number, bluetooth ID.

active  string optional  
Filter devices by active status (available: 0 - only inactive, 1 - only active, -1 - all users). Default: 1.

amputee  integer optional  
Filter devices by amputees. Provide single ID (amputee=1), array of IDs (amputee[]=1&utee[]=2) or comma-separated list of IDs (amputee=1,2). Pass value 0 to get devices unassigned to any amputee.

model  integer optional  
Filter devices by device models. Provide single ID (model=1), array of IDs (model[]=1&model[]=2) or comma-separated list of IDs (model=1,2). Pass value 0 to get devices without model.

extend  string optional  
Comma-separated list of relation extensions (available: model, amputee, clinicians, firmwareVersion, pcbVersion, config).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

sortby  string optional  
Sort by field (available: serial, amputee_name, date). Default: date (desc).

sortdir  string optional  
Sort direction (available: asc, desc).

Get device information

requires authentication supports: extending models

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/device/15?extend=model%2C+amputee%2C+firmwareVersion%2C+pcbVersion%2C+clinicians" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/15"
);

let params = {
    "extend": "model, amputee, firmwareVersion, pcbVersion, clinicians",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view device data"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (200):

{
    "id": 5894,
    "serial": "e45da17a-2f5a-39ef-9154-ce623f6777e8",
    "bluetooth_id": "b2b5a61d-ef53-3a44-a5c2-463e28a6ac63",
    "model_id": 196,
    "amputee_id": 14930,
    "firmware_version_id": 235,
    "pcb_version_id": 138,
    "active": 1,
    "last_activity_at": "0000-00-00 00:00:00",
    "created_at": "2025-01-08T10:15:40.000000Z",
    "updated_at": "2025-01-08T10:15:40.000000Z",
    "model": {
        "id": 196,
        "name": "Zeus hand v1",
        "type": "leg",
        "orientation": "right",
        "active": 1,
        "created_at": "2025-01-08T10:15:40.000000Z",
        "updated_at": "2025-01-08T10:15:40.000000Z"
    },
    "amputee": {
        "id": 14930,
        "mrn": "F8T7T7RJ",
        "name": "Dameon McLaughlin",
        "email": "1736331340hschamberger@example.org",
        "language": "en",
        "phone": "716.934.9666",
        "phone_country": "CG",
        "phone_verified_at": null,
        "address1": "42779 Darius Common",
        "address2": "Carolineport, WY 85538-2048",
        "postal_code": "44958-3670",
        "city": "Luettgen-Satterfield",
        "clinic_name": "Quincystad",
        "clinic_location": "7260 Leffler Coves\nWymanborough, VA 78778-1670",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:40.000000Z",
        "updated_at": "2025-01-08T10:15:40.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "pcb_version": {
        "id": 138,
        "name": "1.63.40",
        "created_at": "2025-01-08T10:15:40.000000Z",
        "updated_at": "2025-01-08T10:15:40.000000Z"
    }
}

Request   

GET api/device/{id}

URL Parameters

id  integer  
Device ID

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: model, amputee, firmwareVersion, pcbVersion, clinicians).

Create new device

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/device" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"serial":"S3R1AL-NUM83R","bluetooth_id":"BL0123456789","model_id":1,"amputee_id":1,"clinicians":"pariatur","firmware_version_id":1,"pcb_version_id":1,"active":true,"last_activity_at":"2022-08-15 12:00:00"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "serial": "S3R1AL-NUM83R",
    "bluetooth_id": "BL0123456789",
    "model_id": 1,
    "amputee_id": 1,
    "clinicians": "pariatur",
    "firmware_version_id": 1,
    "pcb_version_id": 1,
    "active": true,
    "last_activity_at": "2022-08-15 12:00:00"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create device"
}

Example response (403, Firmware has no schema):

{
    "message": "Cannot create: firmware has no schema"
}

Example response (500, Server error):

{
    "message": "Server error: device not created"
}

Example response (201):

{
    "id": 5895,
    "serial": "2be99ae1-d79a-3818-a858-8f9481f0bb1b",
    "bluetooth_id": "4bb14cbe-ca01-38c9-a4e5-db6046348526",
    "model_id": null,
    "amputee_id": null,
    "firmware_version_id": null,
    "pcb_version_id": null,
    "active": 1,
    "last_activity_at": "0000-00-00 00:00:00",
    "created_at": "2025-01-08T10:15:40.000000Z",
    "updated_at": "2025-01-08T10:15:40.000000Z"
}

Request   

POST api/device

Body Parameters

serial  string  
Device serial number.

bluetooth_id  string  
Device Bluetooth ID.

model_id  string  
Device Model ID.

amputee_id  string optional  
Device amputee ID.

clinicians  array optional  
Array of clinician IDs.

firmware_version_id  string optional  
Firmware Version ID.

pcb_version_id  string optional  
PCB Version ID.

active  boolean optional  
Device active status (0 - inactive, 1 - active).

last_activity_at  string optional  
Device last activity date. Update this value each time device connects to the mobile app. Always shift local datetime to UTC timezone. The value must be a valid date in the format Y-m-d H:i:s.

Update device

requires authentication

Amputee of device can update only these fields: serial, bluetooth_id, firmware_version_id, pcb_version_id

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"serial":"S3R1AL-NUM83R","bluetooth_id":"BL0123456789","model_id":1,"amputee_id":1,"clinicians":"quisquam","firmware_version_id":1,"pcb_version_id":1,"active":true,"last_activity_at":"2022-08-15 12:00:00"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "serial": "S3R1AL-NUM83R",
    "bluetooth_id": "BL0123456789",
    "model_id": 1,
    "amputee_id": 1,
    "clinicians": "quisquam",
    "firmware_version_id": 1,
    "pcb_version_id": 1,
    "active": true,
    "last_activity_at": "2022-08-15 12:00:00"
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update device"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (403, Device has active code):

{
    "message": "Cannot update: device has active code",
    "code": "DEVICE:UPDATE:ACTIVE_CODE_EXISTS"
}

Example response (403, Firmware has no schema):

{
    "message": "Cannot update: firmware has no schema",
    "code": "DEVICE:UPDATE:INVALID_FIRMWARE_SCHEMA"
}

Example response (202):

{
    "id": 5896,
    "serial": "22dac2eb-bd0b-3397-8f13-74a788ee440d",
    "bluetooth_id": "a8a67666-42b7-3b68-a3e0-f9fcd595f7bc",
    "model_id": null,
    "amputee_id": null,
    "firmware_version_id": null,
    "pcb_version_id": null,
    "active": 1,
    "last_activity_at": "0000-00-00 00:00:00",
    "created_at": "2025-01-08T10:15:40.000000Z",
    "updated_at": "2025-01-08T10:15:40.000000Z"
}

Request   

PUT api/device/{id}

URL Parameters

id  integer  
Device ID.

Body Parameters

serial  string optional  
Device serial number.

bluetooth_id  string optional  
Device Bluetooth ID.

model_id  string optional  
Device Model ID.

amputee_id  string optional  
Device amputee ID. Pass null to remove assignment.

clinicians  array optional  
Array of clinician IDs.

firmware_version_id  string optional  
Firmware Version ID.

pcb_version_id  string optional  
PCB Version ID.

active  boolean optional  
Device active status (0 - inactive, 1 - active).

last_activity_at  string optional  
Device last activity date. Update this value each time device connects to the mobile app. Always shift local datetime to UTC timezone. The value must be a valid date in the format Y-m-d H:i:s.

Delete device

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to delete device"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (202):

{
    "message": "Device deleted"
}

Request   

DELETE api/device/{id}

URL Parameters

id  integer  
Device ID.

Get device hashes

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/device/1/hash" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/hash"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to access device hashes"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (200):

{
    "hash_global": "123456789012345",
    "hash_common_settings": "123456789012345",
    "hash_common_grips": "123456789012345",
    "hash_mode1": "123456789012345",
    "hash_mode2": "123456789012345",
    "hash_mode3": "123456789012345"
}

Request   

GET api/device/{id}/hash

URL Parameters

id  integer  
Device ID.

Update device hashes

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/hash" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"hash_global":"123456789012345","hash_common_settings":"123456789012345","hash_common_grips":"123456789012345","hash_mode1":"123456789012345","hash_mode2":"123456789012345","hash_mode3":"123456789012345"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/hash"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "hash_global": "123456789012345",
    "hash_common_settings": "123456789012345",
    "hash_common_grips": "123456789012345",
    "hash_mode1": "123456789012345",
    "hash_mode2": "123456789012345",
    "hash_mode3": "123456789012345"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to access device hashes"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (202):

{
    "hash_global": "123456789012345",
    "hash_common_settings": "123456789012345",
    "hash_common_grips": "123456789012345",
    "hash_mode1": "123456789012345",
    "hash_mode2": "123456789012345",
    "hash_mode3": "123456789012345"
}

Request   

POST api/device/{id}/hash

URL Parameters

id  integer  
Device ID.

Body Parameters

hash_global  string optional  
Global hash.

hash_common_settings  string optional  
Common settings hash.

hash_common_grips  string optional  
Common grips hash.

hash_mode1  string optional  
Mode 1 hash.

hash_mode2  string optional  
Mode 2 hash.

hash_mode3  string optional  
Mode 3 hash.

Detach device

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/detach" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/1/detach"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to detach device"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (403, Device has patient assigned):

{
    "message": "Device has patient assigned"
}

Example response (202):

{
    "message": "Device detached"
}

Request   

POST api/device/{id}/detach

URL Parameters

id  integer  
Device ID.

Add device

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/device/add/S3R1AL-NUM83R" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/device/add/S3R1AL-NUM83R"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to assign devices with code"
}

Example response (202):

{
    "id": 5897,
    "serial": "e06507ae-5604-3e09-90d9-db216c331bf3",
    "bluetooth_id": "cb4565d0-c6f6-3bb7-879a-958c12a159c5",
    "model_id": null,
    "amputee_id": null,
    "firmware_version_id": null,
    "pcb_version_id": null,
    "active": 1,
    "last_activity_at": "0000-00-00 00:00:00",
    "created_at": "2025-01-08T10:15:40.000000Z",
    "updated_at": "2025-01-08T10:15:40.000000Z"
}

Request   

POST api/device/add/{serial}

URL Parameters

serial  string  
Device serial number or bluetooth ID.

Documents

API endpoints for documents management

List documents

requires authentication supports: pagination

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/documents?type=0&perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/documents"
);

let params = {
    "type": "0",
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 5,
            "name": "Roustabouts",
            "type": "mobile",
            "created_at": "2025-01-08T10:15:53.000000Z",
            "updated_at": "2025-01-08T10:15:53.000000Z"
        },
        {
            "id": 6,
            "name": "Auditor",
            "type": "mobile",
            "created_at": "2025-01-08T10:15:53.000000Z",
            "updated_at": "2025-01-08T10:15:53.000000Z"
        }
    ]
}

Request   

GET api/documents

Query Parameters

type  integer optional  
Filter documents by type.

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Create document

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/documents" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Privacy Policy","type":"web"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/documents"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Privacy Policy",
    "type": "web"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage documents"
}

Example response (201):

{
    "id": 7,
    "name": "Mail Machine Operator",
    "type": "web",
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

POST api/documents

Body Parameters

name  string  
Document name.

type  string  
Document destination. The value must be one of web or mobile.

Delete document

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/documents/13" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/documents/13"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage documents"
}

Example response (404, Document not found):

{
    "message": "Document not found"
}

Example response (403, Document has existing versions):

{
    "message": "Cannot delete: document has existing versions (1)"
}

Example response (202):

{
    "message": "Document deleted"
}

Request   

DELETE api/documents/{documentId}

URL Parameters

documentId  integer  
Document ID

List document versions

requires authentication supports: pagination

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/documents/17/versions?perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/documents/17/versions"
);

let params = {
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (404, Document not found):

{
    "message": "Document not found"
}

Example response (200):

[
    {
        "id": 7,
        "document_id": null,
        "index": 7604,
        "file": "https:\/\/moen.com\/ab-quod-animi-quae-ea-vel-est-mollitia.html",
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    },
    {
        "id": 8,
        "document_id": null,
        "index": 60960186,
        "file": "http:\/\/treutel.net\/velit-rem-cupiditate-quaerat-repellendus.html",
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    }
]

Request   

GET api/documents/{documentId}/versions

URL Parameters

documentId  integer  
Document ID

Query Parameters

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Create document version

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/documents/12/versions" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"file":"https:\/\/www.aetherbiomedical.com\/privacy-policy"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/documents/12/versions"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "file": "https:\/\/www.aetherbiomedical.com\/privacy-policy"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage documents"
}

Example response (404, Document not found):

{
    "message": "Document not found"
}

Example response (201):

{
    "id": 9,
    "document_id": null,
    "index": 131606738,
    "file": "https:\/\/www.okon.org\/reiciendis-quibusdam-beatae-modi-quisquam-eius",
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

POST api/documents/{documentId}/versions

URL Parameters

documentId  integer  
Document ID

Body Parameters

file  string  
URL to document file. The value must be a valid URL.

Delete document version

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/documents/3/versions/19" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/documents/3/versions/19"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage documents"
}

Example response (404, Document not found):

{
    "message": "Document not found"
}

Example response (404, Document version not found):

{
    "message": "Document version not found"
}

Example response (202):

{
    "message": "Document version deleted"
}

Request   

DELETE api/documents/{documentId}/versions/{versionId}

URL Parameters

documentId  integer  
Document ID

versionId  integer  
DocumentVersion ID

Get documents status

requires authentication

Any document on the list has to be accepted. Use POST /documents/accept endpoint to mark them as accepted once user agrees to that. Empty list means that user is up-to-date with all required documents and nothing has to be accepted.

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/documents/status?type=web" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/documents/status"
);

let params = {
    "type": "web",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view documents status"
}

Example response (200):

{
    "documents": [],
    "texts": {
        "title": "Changes to the Privacy Policy",
        "description": "Due to the addition of a new data processing entity, please familiarize yourself with and accept the new privacy policy",
        "checkbox": "I declare that I have read the content of the Privacy Policy and the Terms and Conditions and accept their provisions. I understand that acceptance is a condition for using the application."
    }
}

Request   

GET api/documents/status

Query Parameters

type  string optional  
Filter documents by type. The value must be one of web or mobile.

Accept documents

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/documents/accept" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"documents":[1,18]}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/documents/accept"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "documents": [
        1,
        18
    ]
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update documents status"
}

Example response (202):

{
    "message": "Accepted 1 document(s)"
}

Request   

POST api/documents/accept

Body Parameters

documents  integer[]  
Document Version ID.

Endpoints

slack

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/slack" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/slack"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request   

POST slack

GeoData

Get supported timezones list

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/timezones" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/timezones"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

[
    "Africa\/Abidjan",
    "Africa\/Accra",
    "Africa\/Addis_Ababa",
    "Africa\/Algiers",
    "Africa\/Asmara",
    "Africa\/Bamako",
    "Africa\/Bangui",
    "Africa\/Banjul",
    "Africa\/Bissau",
    "Africa\/Blantyre",
    "Africa\/Brazzaville",
    "Africa\/Bujumbura",
    "Africa\/Cairo",
    "Africa\/Casablanca",
    "Africa\/Ceuta",
    "Africa\/Conakry",
    "Africa\/Dakar",
    "Africa\/Dar_es_Salaam",
    "Africa\/Djibouti",
    "Africa\/Douala",
    "Africa\/El_Aaiun",
    "Africa\/Freetown",
    "Africa\/Gaborone",
    "Africa\/Harare",
    "Africa\/Johannesburg",
    "Africa\/Juba",
    "Africa\/Kampala",
    "Africa\/Khartoum",
    "Africa\/Kigali",
    "Africa\/Kinshasa",
    "Africa\/Lagos",
    "Africa\/Libreville",
    "Africa\/Lome",
    "Africa\/Luanda",
    "Africa\/Lubumbashi",
    "Africa\/Lusaka",
    "Africa\/Malabo",
    "Africa\/Maputo",
    "Africa\/Maseru",
    "Africa\/Mbabane",
    "Africa\/Mogadishu",
    "Africa\/Monrovia",
    "Africa\/Nairobi",
    "Africa\/Ndjamena",
    "Africa\/Niamey",
    "Africa\/Nouakchott",
    "Africa\/Ouagadougou",
    "Africa\/Porto-Novo",
    "Africa\/Sao_Tome",
    "Africa\/Tripoli",
    "Africa\/Tunis",
    "Africa\/Windhoek",
    "America\/Adak",
    "America\/Anchorage",
    "America\/Anguilla",
    "America\/Antigua",
    "America\/Araguaina",
    "America\/Argentina\/Buenos_Aires",
    "America\/Argentina\/Catamarca",
    "America\/Argentina\/Cordoba",
    "America\/Argentina\/Jujuy",
    "America\/Argentina\/La_Rioja",
    "America\/Argentina\/Mendoza",
    "America\/Argentina\/Rio_Gallegos",
    "America\/Argentina\/Salta",
    "America\/Argentina\/San_Juan",
    "America\/Argentina\/San_Luis",
    "America\/Argentina\/Tucuman",
    "America\/Argentina\/Ushuaia",
    "America\/Aruba",
    "America\/Asuncion",
    "America\/Atikokan",
    "America\/Bahia",
    "America\/Bahia_Banderas",
    "America\/Barbados",
    "America\/Belem",
    "America\/Belize",
    "America\/Blanc-Sablon",
    "America\/Boa_Vista",
    "America\/Bogota",
    "America\/Boise",
    "America\/Cambridge_Bay",
    "America\/Campo_Grande",
    "America\/Cancun",
    "America\/Caracas",
    "America\/Cayenne",
    "America\/Cayman",
    "America\/Chicago",
    "America\/Chihuahua",
    "America\/Costa_Rica",
    "America\/Creston",
    "America\/Cuiaba",
    "America\/Curacao",
    "America\/Danmarkshavn",
    "America\/Dawson",
    "America\/Dawson_Creek",
    "America\/Denver",
    "America\/Detroit",
    "America\/Dominica",
    "America\/Edmonton",
    "America\/Eirunepe",
    "America\/El_Salvador",
    "America\/Fort_Nelson",
    "America\/Fortaleza",
    "America\/Glace_Bay",
    "America\/Goose_Bay",
    "America\/Grand_Turk",
    "America\/Grenada",
    "America\/Guadeloupe",
    "America\/Guatemala",
    "America\/Guayaquil",
    "America\/Guyana",
    "America\/Halifax",
    "America\/Havana",
    "America\/Hermosillo",
    "America\/Indiana\/Indianapolis",
    "America\/Indiana\/Knox",
    "America\/Indiana\/Marengo",
    "America\/Indiana\/Petersburg",
    "America\/Indiana\/Tell_City",
    "America\/Indiana\/Vevay",
    "America\/Indiana\/Vincennes",
    "America\/Indiana\/Winamac",
    "America\/Inuvik",
    "America\/Iqaluit",
    "America\/Jamaica",
    "America\/Juneau",
    "America\/Kentucky\/Louisville",
    "America\/Kentucky\/Monticello",
    "America\/Kralendijk",
    "America\/La_Paz",
    "America\/Lima",
    "America\/Los_Angeles",
    "America\/Lower_Princes",
    "America\/Maceio",
    "America\/Managua",
    "America\/Manaus",
    "America\/Marigot",
    "America\/Martinique",
    "America\/Matamoros",
    "America\/Mazatlan",
    "America\/Menominee",
    "America\/Merida",
    "America\/Metlakatla",
    "America\/Mexico_City",
    "America\/Miquelon",
    "America\/Moncton",
    "America\/Monterrey",
    "America\/Montevideo",
    "America\/Montserrat",
    "America\/Nassau",
    "America\/New_York",
    "America\/Nipigon",
    "America\/Nome",
    "America\/Noronha",
    "America\/North_Dakota\/Beulah",
    "America\/North_Dakota\/Center",
    "America\/North_Dakota\/New_Salem",
    "America\/Nuuk",
    "America\/Ojinaga",
    "America\/Panama",
    "America\/Pangnirtung",
    "America\/Paramaribo",
    "America\/Phoenix",
    "America\/Port-au-Prince",
    "America\/Port_of_Spain",
    "America\/Porto_Velho",
    "America\/Puerto_Rico",
    "America\/Punta_Arenas",
    "America\/Rainy_River",
    "America\/Rankin_Inlet",
    "America\/Recife",
    "America\/Regina",
    "America\/Resolute",
    "America\/Rio_Branco",
    "America\/Santarem",
    "America\/Santiago",
    "America\/Santo_Domingo",
    "America\/Sao_Paulo",
    "America\/Scoresbysund",
    "America\/Sitka",
    "America\/St_Barthelemy",
    "America\/St_Johns",
    "America\/St_Kitts",
    "America\/St_Lucia",
    "America\/St_Thomas",
    "America\/St_Vincent",
    "America\/Swift_Current",
    "America\/Tegucigalpa",
    "America\/Thule",
    "America\/Thunder_Bay",
    "America\/Tijuana",
    "America\/Toronto",
    "America\/Tortola",
    "America\/Vancouver",
    "America\/Whitehorse",
    "America\/Winnipeg",
    "America\/Yakutat",
    "America\/Yellowknife",
    "Antarctica\/Casey",
    "Antarctica\/Davis",
    "Antarctica\/DumontDUrville",
    "Antarctica\/Macquarie",
    "Antarctica\/Mawson",
    "Antarctica\/McMurdo",
    "Antarctica\/Palmer",
    "Antarctica\/Rothera",
    "Antarctica\/Syowa",
    "Antarctica\/Troll",
    "Antarctica\/Vostok",
    "Arctic\/Longyearbyen",
    "Asia\/Aden",
    "Asia\/Almaty",
    "Asia\/Amman",
    "Asia\/Anadyr",
    "Asia\/Aqtau",
    "Asia\/Aqtobe",
    "Asia\/Ashgabat",
    "Asia\/Atyrau",
    "Asia\/Baghdad",
    "Asia\/Bahrain",
    "Asia\/Baku",
    "Asia\/Bangkok",
    "Asia\/Barnaul",
    "Asia\/Beirut",
    "Asia\/Bishkek",
    "Asia\/Brunei",
    "Asia\/Chita",
    "Asia\/Choibalsan",
    "Asia\/Colombo",
    "Asia\/Damascus",
    "Asia\/Dhaka",
    "Asia\/Dili",
    "Asia\/Dubai",
    "Asia\/Dushanbe",
    "Asia\/Famagusta",
    "Asia\/Gaza",
    "Asia\/Hebron",
    "Asia\/Ho_Chi_Minh",
    "Asia\/Hong_Kong",
    "Asia\/Hovd",
    "Asia\/Irkutsk",
    "Asia\/Jakarta",
    "Asia\/Jayapura",
    "Asia\/Jerusalem",
    "Asia\/Kabul",
    "Asia\/Kamchatka",
    "Asia\/Karachi",
    "Asia\/Kathmandu",
    "Asia\/Khandyga",
    "Asia\/Kolkata",
    "Asia\/Krasnoyarsk",
    "Asia\/Kuala_Lumpur",
    "Asia\/Kuching",
    "Asia\/Kuwait",
    "Asia\/Macau",
    "Asia\/Magadan",
    "Asia\/Makassar",
    "Asia\/Manila",
    "Asia\/Muscat",
    "Asia\/Nicosia",
    "Asia\/Novokuznetsk",
    "Asia\/Novosibirsk",
    "Asia\/Omsk",
    "Asia\/Oral",
    "Asia\/Phnom_Penh",
    "Asia\/Pontianak",
    "Asia\/Pyongyang",
    "Asia\/Qatar",
    "Asia\/Qostanay",
    "Asia\/Qyzylorda",
    "Asia\/Riyadh",
    "Asia\/Sakhalin",
    "Asia\/Samarkand",
    "Asia\/Seoul",
    "Asia\/Shanghai",
    "Asia\/Singapore",
    "Asia\/Srednekolymsk",
    "Asia\/Taipei",
    "Asia\/Tashkent",
    "Asia\/Tbilisi",
    "Asia\/Tehran",
    "Asia\/Thimphu",
    "Asia\/Tokyo",
    "Asia\/Tomsk",
    "Asia\/Ulaanbaatar",
    "Asia\/Urumqi",
    "Asia\/Ust-Nera",
    "Asia\/Vientiane",
    "Asia\/Vladivostok",
    "Asia\/Yakutsk",
    "Asia\/Yangon",
    "Asia\/Yekaterinburg",
    "Asia\/Yerevan",
    "Atlantic\/Azores",
    "Atlantic\/Bermuda",
    "Atlantic\/Canary",
    "Atlantic\/Cape_Verde",
    "Atlantic\/Faroe",
    "Atlantic\/Madeira",
    "Atlantic\/Reykjavik",
    "Atlantic\/South_Georgia",
    "Atlantic\/St_Helena",
    "Atlantic\/Stanley",
    "Australia\/Adelaide",
    "Australia\/Brisbane",
    "Australia\/Broken_Hill",
    "Australia\/Darwin",
    "Australia\/Eucla",
    "Australia\/Hobart",
    "Australia\/Lindeman",
    "Australia\/Lord_Howe",
    "Australia\/Melbourne",
    "Australia\/Perth",
    "Australia\/Sydney",
    "Europe\/Amsterdam",
    "Europe\/Andorra",
    "Europe\/Astrakhan",
    "Europe\/Athens",
    "Europe\/Belgrade",
    "Europe\/Berlin",
    "Europe\/Bratislava",
    "Europe\/Brussels",
    "Europe\/Bucharest",
    "Europe\/Budapest",
    "Europe\/Busingen",
    "Europe\/Chisinau",
    "Europe\/Copenhagen",
    "Europe\/Dublin",
    "Europe\/Gibraltar",
    "Europe\/Guernsey",
    "Europe\/Helsinki",
    "Europe\/Isle_of_Man",
    "Europe\/Istanbul",
    "Europe\/Jersey",
    "Europe\/Kaliningrad",
    "Europe\/Kiev",
    "Europe\/Kirov",
    "Europe\/Lisbon",
    "Europe\/Ljubljana",
    "Europe\/London",
    "Europe\/Luxembourg",
    "Europe\/Madrid",
    "Europe\/Malta",
    "Europe\/Mariehamn",
    "Europe\/Minsk",
    "Europe\/Monaco",
    "Europe\/Moscow",
    "Europe\/Oslo",
    "Europe\/Paris",
    "Europe\/Podgorica",
    "Europe\/Prague",
    "Europe\/Riga",
    "Europe\/Rome",
    "Europe\/Samara",
    "Europe\/San_Marino",
    "Europe\/Sarajevo",
    "Europe\/Saratov",
    "Europe\/Simferopol",
    "Europe\/Skopje",
    "Europe\/Sofia",
    "Europe\/Stockholm",
    "Europe\/Tallinn",
    "Europe\/Tirane",
    "Europe\/Ulyanovsk",
    "Europe\/Uzhgorod",
    "Europe\/Vaduz",
    "Europe\/Vatican",
    "Europe\/Vienna",
    "Europe\/Vilnius",
    "Europe\/Volgograd",
    "Europe\/Warsaw",
    "Europe\/Zagreb",
    "Europe\/Zaporozhye",
    "Europe\/Zurich",
    "Indian\/Antananarivo",
    "Indian\/Chagos",
    "Indian\/Christmas",
    "Indian\/Cocos",
    "Indian\/Comoro",
    "Indian\/Kerguelen",
    "Indian\/Mahe",
    "Indian\/Maldives",
    "Indian\/Mauritius",
    "Indian\/Mayotte",
    "Indian\/Reunion",
    "Pacific\/Apia",
    "Pacific\/Auckland",
    "Pacific\/Bougainville",
    "Pacific\/Chatham",
    "Pacific\/Chuuk",
    "Pacific\/Easter",
    "Pacific\/Efate",
    "Pacific\/Fakaofo",
    "Pacific\/Fiji",
    "Pacific\/Funafuti",
    "Pacific\/Galapagos",
    "Pacific\/Gambier",
    "Pacific\/Guadalcanal",
    "Pacific\/Guam",
    "Pacific\/Honolulu",
    "Pacific\/Kanton",
    "Pacific\/Kiritimati",
    "Pacific\/Kosrae",
    "Pacific\/Kwajalein",
    "Pacific\/Majuro",
    "Pacific\/Marquesas",
    "Pacific\/Midway",
    "Pacific\/Nauru",
    "Pacific\/Niue",
    "Pacific\/Norfolk",
    "Pacific\/Noumea",
    "Pacific\/Pago_Pago",
    "Pacific\/Palau",
    "Pacific\/Pitcairn",
    "Pacific\/Pohnpei",
    "Pacific\/Port_Moresby",
    "Pacific\/Rarotonga",
    "Pacific\/Saipan",
    "Pacific\/Tahiti",
    "Pacific\/Tarawa",
    "Pacific\/Tongatapu",
    "Pacific\/Wake",
    "Pacific\/Wallis",
    "UTC"
]

Request   

GET api/timezones

Goals

API endpoints for goals

The goals module consists of:

List grips

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/grips" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/grips"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view grips"
}

Example response (200):

[
    {
        "id": 37,
        "number": 1242,
        "name": "enim grip",
        "description": null,
        "image": null,
        "opposed": 0,
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    },
    {
        "id": 38,
        "number": 1382,
        "name": "et grip",
        "description": null,
        "image": null,
        "opposed": 0,
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    }
]

Request   

GET api/grips

List exercises

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/exercises" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/exercises"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view exercises"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 106,
            "name": "Ondricka Crossing",
            "description": "Natus ea cupiditate officia perspiciatis quisquam similique.",
            "icon": "😞",
            "created_at": "2025-01-08T10:15:54.000000Z",
            "updated_at": "2025-01-08T10:15:54.000000Z"
        },
        {
            "id": 107,
            "name": "Pacocha Lodge",
            "description": "Possimus culpa qui aliquam sit.",
            "icon": "😩",
            "created_at": "2025-01-08T10:15:54.000000Z",
            "updated_at": "2025-01-08T10:15:54.000000Z"
        }
    ]
}

Request   

GET api/exercises

Create exercise

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/exercises" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Water plants","description":"Use Tripod Close Grip and water your plants","icon":"\ud83e\udeb4"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/exercises"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Water plants",
    "description": "Use Tripod Close Grip and water your plants",
    "icon": "\ud83e\udeb4"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage exercises"
}

Example response (201):

{
    "id": 108,
    "name": "Barton Parks",
    "description": "Ipsa quidem accusantium consequatur.",
    "icon": "😥",
    "created_at": "2025-01-08T10:15:54.000000Z",
    "updated_at": "2025-01-08T10:15:54.000000Z"
}

Request   

POST api/exercises

Body Parameters

name  string  
Exercise name.

description  string  
Exercise description.

icon  string  
Emoji icon.

Update exercise

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/exercises/8" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Water plants","description":"Use Tripod Close Grip and water your plants","icon":"\ud83e\udeb4"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/exercises/8"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Water plants",
    "description": "Use Tripod Close Grip and water your plants",
    "icon": "\ud83e\udeb4"
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage exercises"
}

Example response (404, Exercise not found):

{
    "message": "Exercise not found"
}

Example response (202):

{
    "id": 109,
    "name": "Bins Falls",
    "description": "Commodi voluptas porro eius qui corporis odit.",
    "icon": "😨",
    "created_at": "2025-01-08T10:15:54.000000Z",
    "updated_at": "2025-01-08T10:15:54.000000Z"
}

Request   

PUT api/exercises/{exerciseId}

URL Parameters

exerciseId  integer  
Exercise ID

Body Parameters

name  string optional  
Exercise name.

description  string optional  
Exercise description.

icon  string optional  
Emoji icon.

Delete exercise

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/exercises/5" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/exercises/5"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage exercises"
}

Example response (404, Exercise not found):

{
    "message": "Exercise not found"
}

Example response (403, Exercise is used in goals):

{
    "message": "Cannot delete: exercise is used in goals (1)"
}

Example response (202):

{
    "message": "Exercise deleted"
}

Request   

DELETE api/exercises/{exerciseId}

URL Parameters

exerciseId  integer  
Exercise ID

List user goals

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/user/12/goals" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/12/goals"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view user goals"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 108,
            "amputee_id": 15088,
            "clinician_id": 15089,
            "start_date": "2015-09-24",
            "end_date": "1998-11-01",
            "active": 1,
            "created_at": "2025-01-08T10:15:54.000000Z",
            "updated_at": "2025-01-08T10:15:54.000000Z"
        },
        {
            "id": 109,
            "amputee_id": 15090,
            "clinician_id": 15091,
            "start_date": "1982-03-02",
            "end_date": "2012-02-12",
            "active": 1,
            "created_at": "2025-01-08T10:15:54.000000Z",
            "updated_at": "2025-01-08T10:15:54.000000Z"
        }
    ]
}

Request   

GET api/user/{userId}/goals

URL Parameters

userId  integer  
User ID

Create user goal

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/20/goals" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"start_date":"2023-05-12","end_date":"2023-05-15","active":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/20/goals"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "start_date": "2023-05-12",
    "end_date": "2023-05-15",
    "active": 1
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage user goals"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (201):

{
    "id": 110,
    "amputee_id": 15092,
    "clinician_id": 15093,
    "start_date": "2015-01-02",
    "end_date": "2019-06-20",
    "active": 0,
    "created_at": "2025-01-08T10:15:54.000000Z",
    "updated_at": "2025-01-08T10:15:54.000000Z"
}

Request   

POST api/user/{userId}/goals

URL Parameters

userId  integer  
User ID

Body Parameters

start_date  string  
Start date of the goal tracking The value must be a valid date. The value must be a valid date in the format Y-m-d.

end_date  string  
End date of goal tracking The value must be a valid date. The value must be a valid date in the format Y-m-d.

active  integer optional  
Status of goal activity The value must be one of 0 or 1.

Update user goal

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/4/goals/8" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"start_date":"2023-05-12","end_date":"2023-05-15","active":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/4/goals/8"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "start_date": "2023-05-12",
    "end_date": "2023-05-15",
    "active": 1
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage user goals"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (404, Goal not found):

{
    "message": "Goal not found"
}

Example response (403, Cannot activate ongoing goal):

{
    "message": "Cannot activate ongoing goal"
}

Example response (202):

{
    "id": 111,
    "amputee_id": 15094,
    "clinician_id": 15095,
    "start_date": "1998-08-29",
    "end_date": "2017-04-12",
    "active": 0,
    "created_at": "2025-01-08T10:15:54.000000Z",
    "updated_at": "2025-01-08T10:15:54.000000Z"
}

Request   

PUT api/user/{userId}/goals/{goalId}

URL Parameters

userId  integer  
User ID

goalId  integer  
Goal ID

Body Parameters

start_date  string optional  
Start date of the goal tracking The value must be a valid date. The value must be a valid date in the format Y-m-d.

end_date  string optional  
End date of goal tracking The value must be a valid date. The value must be a valid date in the format Y-m-d.

active  integer optional  
Status of goal activity The value must be one of 0 or 1.

Delete user goal

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/15/goals/2" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/15/goals/2"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage user goals"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (404, Goal not found):

{
    "message": "Goal not found"
}

Example response (403, Cannot update ongoing goal):

{
    "message": "Cannot delete active ongoing goal"
}

Example response (202, Goal deleted):

{
    "message": "Goal deleted"
}

Request   

DELETE api/user/{userId}/goals/{goalId}

URL Parameters

userId  integer  
User ID

goalId  integer  
Goal ID

List user goal conditions

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/user/19/goals/6/conditions" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/19/goals/6/conditions"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view user goals"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (404, Goal not found):

{
    "message": "Goal not found"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 239,
            "goal_id": 112,
            "type": "switch",
            "grip_id": 39,
            "grips_frequency": "d",
            "grips_count": 463,
            "switches_frequency": "m",
            "switches_count": 185,
            "exercise_id": 110,
            "exercise_frequency": "w",
            "exercise_count": 4,
            "created_at": "2025-01-08T10:15:55.000000Z",
            "updated_at": "2025-01-08T10:15:55.000000Z"
        },
        {
            "id": 240,
            "goal_id": 113,
            "type": "exercise",
            "grip_id": 40,
            "grips_frequency": "w",
            "grips_count": 791,
            "switches_frequency": "a",
            "switches_count": 714,
            "exercise_id": 111,
            "exercise_frequency": "d",
            "exercise_count": 1,
            "created_at": "2025-01-08T10:15:55.000000Z",
            "updated_at": "2025-01-08T10:15:55.000000Z"
        }
    ]
}

Request   

GET api/user/{userId}/goals/{goalId}/conditions

URL Parameters

userId  integer  
User ID

goalId  integer  
Goal ID

Create user goal condition

requires authentication

Each goal condition could be one of type: grip, switch or exercise.

If goal condition is type of grip, fill only grip_id (optional), grips_frequency and grips_count.
If grip_id is null or missing, patient can perform any grip to fulfill objective.

If goal condition is type of switch, fill only switches_frequency and switches_count.

If goal condition is type of exercise, fill only exercise_id, exercise_frequency and exercise_count.


Restrictions:

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/11/goals/17/conditions" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"type":"grip","grip_id":1,"grips_frequency":"d","grips_count":100,"switches_frequency":"d","switches_count":100,"exercise_id":1,"exercise_frequency":"d","exercise_count":5}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/11/goals/17/conditions"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "type": "grip",
    "grip_id": 1,
    "grips_frequency": "d",
    "grips_count": 100,
    "switches_frequency": "d",
    "switches_count": 100,
    "exercise_id": 1,
    "exercise_frequency": "d",
    "exercise_count": 5
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage user goals"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (404, Goal not found):

{
    "message": "Goal not found"
}

Example response (403, Cannot create condition: frequency):

{
    "message": "Cannot create condition: all grip conditions have to be same frequency"
}

Example response (403, Cannot create condition: grip-any already exists):

{
    "message": "Cannot create condition: grip-any condition for this goal already exist"
}

Example response (403, Cannot create condition: condition with grip already exists):

{
    "message": "Cannot create condition: condition with this grip already exist"
}

Example response (403, Cannot create condition: grip-any lower than sum of grips):

{
    "message": "Cannot create condition: grip-any value cannot be lower than sum of grip-specific conditions"
}

Example response (403, Cannot create condition: grips sum bigger than grip-any):

{
    "message": "Cannot create condition: sum of grip-specific conditions cannot be greater than value of grip-any condition"
}

Example response (403, Cannot create condition: switch):

{
    "message": "Cannot create condition: switch condition for this goal already exist"
}

Example response (403, Cannot create condition: exercise):

{
    "message": "Cannot create condition: condition with this exercise already exist"
}

Example response (201):

{
    "id": 241,
    "goal_id": 114,
    "type": "grip",
    "grip_id": 41,
    "grips_frequency": "w",
    "grips_count": 139,
    "switches_frequency": "a",
    "switches_count": 380,
    "exercise_id": 112,
    "exercise_frequency": "m",
    "exercise_count": 1,
    "created_at": "2025-01-08T10:15:55.000000Z",
    "updated_at": "2025-01-08T10:15:55.000000Z"
}

Request   

POST api/user/{userId}/goals/{goalId}/conditions

URL Parameters

userId  integer  
User ID

goalId  integer  
Goal ID

Body Parameters

type  string  
Goal condition type. The value must be one of grip, switch, or exercise.

grip_id  integer optional  
Grip number required for condition. Pass null to allow any grip.

grips_frequency  string optional  
Grips frequency unit. d - daily, w - weekly, m - monthly, a - all time (within goal). The value must be one of d, w, m, or a.

grips_count  integer optional  
Required number of grips per frequency unit.

switches_frequency  string optional  
Switches frequency unit. d - daily, w - weekly, m - monthly, a - all time (within goal). The value must be one of d, w, m, or a.

switches_count  integer optional  
Required number of switches per frequency unit.

exercise_id  integer optional  
Exercise ID.

exercise_frequency  string optional  
Exercise frequency unit. d - daily, w - weekly, m - monthly. The value must be one of d, w, or m.

exercise_count  integer optional  
Required number of performed exercises per frequency unit.

Delete user goal condition

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/13/goals/2/conditions/5" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/13/goals/2/conditions/5"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage user goals"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (404, Goal not found):

{
    "message": "Goal not found"
}

Example response (202, Goal condition deleted):

{
    "message": "Goal condition deleted"
}

Request   

DELETE api/user/{userId}/goals/{goalId}/conditions/{conditionId}

URL Parameters

userId  integer  
User ID

goalId  integer  
Goal ID

conditionId  integer  
Goal condition ID

Get user goal progress

requires authentication

Data is grouped into three parts:

For grips and switches there is summary, which is divided into 4 parts:

There are also extra fields inside the summary parts:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/goals/15/progress" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/goals/15/progress"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view goal progress"
}

Example response (404, Goal not found):

{
    "message": "Goal not found"
}

Example response (200):

{
    "grips": {
        "meta": {
            "overall": {
                "from": "2023-09-01 00:00:00",
                "to": "2023-08-30 23:59:59"
            },
            "period": {
                "from": "2023-09-15 23:59:59",
                "to": "2023-09-21 23:59:59",
                "frequency": "w"
            }
        },
        "summary": {
            "type": "grips-specific",
            "progress": 222,
            "goal": 2535
        },
        "progress": [
            {
                "grip": {
                    "id": 1,
                    "number": 0,
                    "name": "Rest Opposition",
                    "description": null,
                    "created_at": "2023-08-30T12:20:00.000000Z",
                    "updated_at": "2023-08-30T12:20:00.000000Z"
                },
                "overall": {
                    "progress": 125,
                    "goal": 200
                },
                "period": {
                    "progress": 22,
                    "goal": 50
                }
            },
            {
                "grip": {
                    "id": 2,
                    "number": 1,
                    "name": "Power",
                    "description": null,
                    "created_at": "2023-05-18T11:24:11.000000Z",
                    "updated_at": "2023-05-18T11:24:11.000000Z"
                },
                "overall": {
                    "progress": 90,
                    "goal": 150
                },
                "period": {
                    "progress": 10,
                    "goal": 30
                }
            },
            {
                "grip": null,
                "overall": {
                    "progress": 78,
                    "goal": 1250
                },
                "period": {
                    "progress": 17,
                    "goal": 240
                }
            }
        ],
        "today": {
            "performed": 0,
            "goal": 0,
            "done": true
        }
    },
    "switches": {
        "overall": {
            "performed": 55,
            "goal": 300
        },
        "period": {
            "performed": 25,
            "goal": 30,
            "frequency": "d",
            "frequency_from": "2023-09-20 00:00:00",
            "frequency_to": "2023-09-20 23:59:59"
        },
        "today": {
            "performed": 25,
            "goal": 30,
            "done": false
        },
        "condition": {
            "type": "switch",
            "switches_frequency": "d",
            "switches_count": 30
        }
    },
    "exercises": {
        "performed": 1,
        "goal": 3,
        "done": false,
        "conditions": [
            {
                "type": "exercise",
                "exercise_id": 1,
                "exercise_frequency": "d",
                "exercise_count": 3,
                "attempts": [
                    {
                        "date_from": "2023-06-06",
                        "date_to": "2023-06-12",
                        "count_done": 1,
                        "count_not_done": 1
                    },
                    {
                        "date_from": "2023-06-13",
                        "date_to": "2023-06-19",
                        "count_done": 0,
                        "count_not_done": 0
                    },
                    {
                        "date_from": "2023-06-20",
                        "date_to": "2023-06-26",
                        "count_done": 0,
                        "count_not_done": 0
                    },
                    {
                        "date_from": "2023-06-27",
                        "date_to": "2023-07-03",
                        "count_done": 0,
                        "count_not_done": 0
                    }
                ],
                "exercise": {
                    "id": 1,
                    "name": "Water plants",
                    "description": "Use Tripod Grip and water your plants",
                    "icon": "🪴",
                    "created_at": "2023-05-19T10:25:37.000000Z",
                    "updated_at": "2023-05-19T10:25:37.000000Z"
                }
            }
        ]
    }
}

Request   

GET api/goals/{goalId}/progress

URL Parameters

goalId  integer  
Goal ID

Update user goal progress

requires authentication

Use this endpoint to update goal progress as patient. Add exercise attempts and mark them as done or not done.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/goals/12/progress" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"exercise_id":1,"exercise_done":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/goals/12/progress"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "exercise_id": 1,
    "exercise_done": 1
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update goal progress"
}

Example response (404, Goal not found):

{
    "message": "Goal not found"
}

Example response (422, User timezone not set):

{
    "message": "User timezone not set"
}

Example response (201):

{
    "id": 792,
    "user_id": 15102,
    "goal_id": 115,
    "type": "exercise",
    "grip_id": null,
    "grips": 100,
    "switches": 926,
    "exercise_id": 113,
    "exercise_done": 1,
    "created_at": "2025-01-08T10:15:55.000000Z",
    "updated_at": "2025-01-08T10:15:55.000000Z"
}

Request   

POST api/goals/{goalId}/progress

URL Parameters

goalId  integer  
Goal ID

Body Parameters

exercise_id  integer  
Exercise ID.

exercise_done  string optional  
Status of exercise attempt. The value must be one of 0 or 1.

Invitations

Accept invitation

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/invite/accept" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"token":"ABC123DEF456GHI789JKL0","email":"example@domain.com","password":"Test123!","language":"ratione","name":"Tom Smith","clinic_name":"My clinic Ltd","clinic_location":"Example St 1\/345 New York, NY","address1":"380 Adolfo Squares Suite 517","address2":"Port Euna, IA 62996-9347","mfa_enabled":true,"mfa_method":"email"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/invite/accept"
);

let headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "token": "ABC123DEF456GHI789JKL0",
    "email": "example@domain.com",
    "password": "Test123!",
    "language": "ratione",
    "name": "Tom Smith",
    "clinic_name": "My clinic Ltd",
    "clinic_location": "Example St 1\/345 New York, NY",
    "address1": "380 Adolfo Squares Suite 517",
    "address2": "Port Euna, IA 62996-9347",
    "mfa_enabled": true,
    "mfa_method": "email"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (404, Invitation not found):

{
    "message": "Invitation not found",
    "code": "INVITE:ACCEPT:INVITATION_NOT_FOUND"
}

Example response (404, Invitation expired):

{
    "message": "Invitation expired",
    "code": "INVITE:ACCEPT:INVITATION_EXPIRED"
}

Example response (500, Server error):

{
    "message": "Server error: invitation not accepted",
    "code": "INVITE:ACCEPT:SERVER_ERROR"
}

Example response (200):

{
    "id": 14916,
    "mrn": "QNYXUA7Q",
    "name": "Keely Tromp IV",
    "email": "1736331338williamson.maddison@example.net",
    "language": "en",
    "phone": "+1-281-299-8317",
    "phone_country": "RS",
    "phone_verified_at": null,
    "address1": "54299 Weber Spurs Suite 578",
    "address2": "Lake Kyla, WV 96543",
    "postal_code": "33251-8111",
    "city": "Langworth-Kirlin",
    "clinic_name": "South Malikastad",
    "clinic_location": "9619 Lenore Crest\nLake Esperanza, MT 22725",
    "image": null,
    "mfa_enabled": 0,
    "mfa_method": null,
    "mfa_verified_to": null,
    "created_by": null,
    "active": 1,
    "notifications_timezone": null,
    "notifications_at": null,
    "created_at": "2025-01-08T10:15:38.000000Z",
    "updated_at": "2025-01-08T10:15:38.000000Z",
    "invitation_status": null,
    "roles": [
        {
            "id": 3,
            "name": "Amputee"
        }
    ]
}

Request   

POST api/invite/accept

Body Parameters

token  string  
Invitation token sent by e-mail.

email  string  
User e-mail. The value must be a valid email address.

password  string  
User password.

language  string  

name  string  
User name.

clinic_name  string optional  
Clinic name.

clinic_location  string optional  
Clinic location.

address1  string optional  
User address line 1.

address2  string optional  
User address line 2.

mfa_enabled  boolean optional  
MFA enabled.

mfa_method  string optional  
MFA method. The value must be one of email or sms.

List users for invitations

requires authentication supports: extending models supports: pagination

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/invite/users?extend=clinicians%2C+patients%2C+devices%2C+devicesAsClinician%2C+roles%2C+permissions&perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/invite/users"
);

let params = {
    "extend": "clinicians, patients, devices, devicesAsClinician, roles, permissions",
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to list users for invitations"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 14923,
            "mrn": "WVQU82H4",
            "name": "Roy Bauch",
            "email": "1736331339imelda71@example.org",
            "language": "en",
            "phone": "+1 (360) 757-7379",
            "phone_country": "NF",
            "phone_verified_at": null,
            "address1": "665 Kozey Pass Suite 301",
            "address2": "West Destini, AL 87384-7625",
            "postal_code": "66680-0093",
            "city": "Harris-Cartwright",
            "clinic_name": "Rutherfordstad",
            "clinic_location": "78980 Manley Plaza\nWildermanstad, AZ 16371-2238",
            "image": null,
            "mfa_enabled": 0,
            "mfa_method": null,
            "mfa_verified_to": null,
            "created_by": null,
            "active": 1,
            "notifications_timezone": null,
            "notifications_at": null,
            "created_at": "2025-01-08T10:15:39.000000Z",
            "updated_at": "2025-01-08T10:15:39.000000Z",
            "invitation_status": null,
            "roles": [
                {
                    "id": 3,
                    "name": "Amputee"
                }
            ]
        },
        {
            "id": 14924,
            "mrn": "P83069R5",
            "name": "Jocelyn Hill",
            "email": "1736331339grant.trinity@example.org",
            "language": "en",
            "phone": "508.962.3756",
            "phone_country": "FR",
            "phone_verified_at": null,
            "address1": "5216 Beer Inlet Apt. 253",
            "address2": "Eichmannmouth, MD 39503-5472",
            "postal_code": "72405",
            "city": "Wisoky Group",
            "clinic_name": "Westside",
            "clinic_location": "4280 Herzog Well\nBorerhaven, VA 77207",
            "image": null,
            "mfa_enabled": 0,
            "mfa_method": null,
            "mfa_verified_to": null,
            "created_by": null,
            "active": 1,
            "notifications_timezone": null,
            "notifications_at": null,
            "created_at": "2025-01-08T10:15:39.000000Z",
            "updated_at": "2025-01-08T10:15:39.000000Z",
            "invitation_status": null,
            "roles": [
                {
                    "id": 3,
                    "name": "Amputee"
                }
            ]
        }
    ]
}

Request   

GET api/invite/users

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: clinicians, patients, devices, devicesAsClinician, roles, permissions).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Create invitations

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/invite" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"patient_id":1,"invitations":[{"user_id":1,"user_email":"newuser@domain.com","role":"Clinician","training_confirmed":true,"permissions":["sequi","animi"]},{"user_id":1,"user_email":"newuser@domain.com","training_confirmed":true,"permissions":["sequi","ex"]}]}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/invite"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "patient_id": 1,
    "invitations": [
        {
            "user_id": 1,
            "user_email": "newuser@domain.com",
            "role": "Clinician",
            "training_confirmed": true,
            "permissions": [
                "sequi",
                "animi"
            ]
        },
        {
            "user_id": 1,
            "user_email": "newuser@domain.com",
            "training_confirmed": true,
            "permissions": [
                "sequi",
                "ex"
            ]
        }
    ]
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create invitations"
}

Example response (403, No access to given patient):

{
    "message": "No access to given patient"
}

Example response (201):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 10,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 14925,
            "mrn": "O5J9437K",
            "name": "Wilhelmine Morar",
            "email": "1736331339jenkins.fermin@example.net",
            "language": "en",
            "phone": "+1-269-538-4086",
            "phone_country": "MW",
            "phone_verified_at": null,
            "address1": "1611 Jaron Alley",
            "address2": "New Claudinemouth, MD 84691-0947",
            "postal_code": "54633",
            "city": "Mayert, Bauch and Emard",
            "clinic_name": "New Devante",
            "clinic_location": "3299 Muhammad Canyon Suite 335\nDestanystad, MO 10312-4451",
            "image": null,
            "mfa_enabled": 0,
            "mfa_method": null,
            "mfa_verified_to": null,
            "created_by": null,
            "active": 1,
            "notifications_timezone": null,
            "notifications_at": null,
            "created_at": "2025-01-08T10:15:39.000000Z",
            "updated_at": "2025-01-08T10:15:39.000000Z",
            "invitation_status": null,
            "roles": [
                {
                    "id": 3,
                    "name": "Amputee"
                }
            ],
            "invitations": []
        },
        {
            "id": 14926,
            "mrn": "NA2SSCEQ",
            "name": "Amira Weimann",
            "email": "1736331339savanah.rodriguez@example.com",
            "language": "en",
            "phone": "804-684-2389",
            "phone_country": "EH",
            "phone_verified_at": null,
            "address1": "4996 Jaleel Glen Suite 908",
            "address2": "North Silasmouth, NC 86221-8896",
            "postal_code": "26365",
            "city": "Swift, Price and Kovacek",
            "clinic_name": "Maverickshire",
            "clinic_location": "78165 Ashley Route\nSouth Amyfurt, DE 56552-5043",
            "image": null,
            "mfa_enabled": 0,
            "mfa_method": null,
            "mfa_verified_to": null,
            "created_by": null,
            "active": 1,
            "notifications_timezone": null,
            "notifications_at": null,
            "created_at": "2025-01-08T10:15:39.000000Z",
            "updated_at": "2025-01-08T10:15:39.000000Z",
            "invitation_status": null,
            "roles": [
                {
                    "id": 3,
                    "name": "Amputee"
                }
            ],
            "invitations": []
        }
    ]
}

Request   

POST api/invite

Body Parameters

patient_id  string  
Patient user ID.

invitations  object[]  
List of invitations (maximum entries: 10, array of objects).

invitations[].user_id  integer optional  
Invited user ID. Use only for existing users. Don't use together with user_email.

invitations[].user_email  string optional  
Invited user e-mail. Use only for non-existing users. Don't use together with user_id. The value must be a valid email address.

invitations[].role  string optional  
Invited user role. Use only for non-existing users. The value must be one of ClinicAdmin, Clinician, or ClinicianSupport.

invitations[].training_confirmed  boolean  
Confirmation that invited user was properly trained to use ADP. The value must be one of 1 or true.

invitations[].permissions  string[] optional  
List of permissions to assign to the user (use that for ClinicianSupport role).

invitations[].permissions[]  string optional  
Permission name.

Resend invitation

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/invite/6/resend" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/invite/6/resend"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to resend invitations"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (403, Invitation already accepted):

{
    "message": "Invitation already accepted",
    "code": "INVITE:RESEND:INVITATION_ACCEPTED"
}

Example response (201):

{
    "id": 14927,
    "mrn": "RX05TB8I",
    "name": "Miss Ernestina Bashirian Sr.",
    "email": "1736331339qmcglynn@example.com",
    "language": "en",
    "phone": "1-469-788-4338",
    "phone_country": "ES",
    "phone_verified_at": null,
    "address1": "872 Tyson Cape Suite 407",
    "address2": "Port Providenciside, DE 37767-2880",
    "postal_code": "89916-8819",
    "city": "Bartoletti PLC",
    "clinic_name": "Port Lupe",
    "clinic_location": "7334 Mann Park Apt. 667\nMaymieland, VA 30171",
    "image": null,
    "mfa_enabled": 0,
    "mfa_method": null,
    "mfa_verified_to": null,
    "created_by": null,
    "active": 1,
    "notifications_timezone": null,
    "notifications_at": null,
    "created_at": "2025-01-08T10:15:39.000000Z",
    "updated_at": "2025-01-08T10:15:39.000000Z",
    "invitation_status": null,
    "roles": [
        {
            "id": 3,
            "name": "Amputee"
        }
    ],
    "invitations": []
}

Request   

POST api/invite/{userId}/resend

URL Parameters

userId  integer  
User ID.

Logs

Get events log

requires authentication supports: pagination supports: sorting

user - user account that performed action
element - element model that has been affected by action

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/logs?search=Test&ip=200.200.100.5&user=1&type=user&date_from=1642003200&date_to=1642003200&include_sessions=1&perpage=20&page=1&sortby=type%2C+username%2C+ip_address%2C+date&sortdir=asc" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/logs"
);

let params = {
    "search": "Test",
    "ip": "200.200.100.5",
    "user": "1",
    "type": "user",
    "date_from": "1642003200",
    "date_to": "1642003200",
    "include_sessions": "1",
    "perpage": "20",
    "page": "1",
    "sortby": "type, username, ip_address, date",
    "sortdir": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to access event logs"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 1065670,
            "user_id": 15105,
            "event_name": "event_factory",
            "element_type": "App\\Models\\User",
            "element_id": 15106,
            "comments": "",
            "ip_address": "8.57.51.228",
            "created_at": "2007-07-15T11:18:43.000000Z",
            "updated_at": "2025-01-08T10:15:55.000000Z",
            "user": {
                "id": 15105,
                "mrn": "VGQEZ0QK",
                "name": "Stan Koss",
                "email": "1736331355imelda05@example.org",
                "language": "en",
                "phone": "941.453.4336",
                "phone_country": "SG",
                "phone_verified_at": null,
                "address1": "3328 Hermiston Ford",
                "address2": "Ettiebury, RI 18346",
                "postal_code": "24504",
                "city": "Spinka Ltd",
                "clinic_name": "Stoltenbergland",
                "clinic_location": "796 Reynolds Plain\nNew Phyllis, ND 33564",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:55.000000Z",
                "updated_at": "2025-01-08T10:15:55.000000Z",
                "invitation_status": null,
                "roles": []
            },
            "element": {
                "id": 15106,
                "mrn": "1SOOF95B",
                "name": "Miss Cortney Mosciski Sr.",
                "email": "1736331355jacey.marvin@example.org",
                "language": "en",
                "phone": "1-628-930-6944",
                "phone_country": "AI",
                "phone_verified_at": null,
                "address1": "62321 Wehner Green",
                "address2": "West Preciouston, MT 88854",
                "postal_code": "75238-9636",
                "city": "Bosco-Durgan",
                "clinic_name": "Coryton",
                "clinic_location": "176 Yvonne Cape Suite 024\nPort Martinefort, RI 00725-5138",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:55.000000Z",
                "updated_at": "2025-01-08T10:15:55.000000Z",
                "invitation_status": null,
                "roles": []
            }
        },
        {
            "id": 1065671,
            "user_id": 15107,
            "event_name": "event_factory",
            "element_type": "App\\Models\\User",
            "element_id": 15108,
            "comments": "",
            "ip_address": "25.91.90.129",
            "created_at": "2007-02-18T09:23:30.000000Z",
            "updated_at": "2025-01-08T10:15:56.000000Z",
            "user": {
                "id": 15107,
                "mrn": "OT0TGQIC",
                "name": "Abdiel Nikolaus",
                "email": "1736331355cornelius.weissnat@example.org",
                "language": "en",
                "phone": "+1 (970) 322-1529",
                "phone_country": "RS",
                "phone_verified_at": null,
                "address1": "53506 Wilkinson Isle Suite 479",
                "address2": "North Antonetteborough, ND 44692-5663",
                "postal_code": "27155-5640",
                "city": "Schmitt-Schroeder",
                "clinic_name": "North Destineebury",
                "clinic_location": "68250 Sarina Curve\nPearlmouth, NJ 55596-2741",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:55.000000Z",
                "updated_at": "2025-01-08T10:15:55.000000Z",
                "invitation_status": null,
                "roles": []
            },
            "element": {
                "id": 15108,
                "mrn": "XY4IUYCG",
                "name": "Prof. Delmer Ratke",
                "email": "1736331355cloyd62@example.org",
                "language": "en",
                "phone": "+1 (938) 986-9721",
                "phone_country": "VI",
                "phone_verified_at": null,
                "address1": "688 Borer Glens Apt. 504",
                "address2": "East Jakebury, AR 21425",
                "postal_code": "95053-9163",
                "city": "Okuneva-Reinger",
                "clinic_name": "Katrinamouth",
                "clinic_location": "369 Blanca Isle Apt. 803\nSouth Jarrell, RI 85421",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:56.000000Z",
                "updated_at": "2025-01-08T10:15:56.000000Z",
                "invitation_status": null,
                "roles": []
            }
        }
    ]
}

Request   

GET api/logs

Query Parameters

search  string optional  
Filter logs by related element data:
- for users: search by name or email
- for devices: search by serial or bluetooth_id
- for P2P sessions: search by amputee_uuid or clinician_uuid.

ip  string optional  
Filter logs by IP address.

user  integer optional  
Filter logs by user.

type  string optional  
Filter logs by event type (available: user, device, p2p_session.

date_from  integer optional  
Filter logs from date (timestamp).

date_to  integer optional  
Filter logs to date (timestamp).

include_sessions  integer optional  
Login and logout events are filtered out by default. Set this parameter to 1 to include these events.

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

sortby  string optional  
Sort by field (available: type, username, ip_address, date). Default: date (desc).

sortdir  string optional  
Sort direction (available: asc, desc).

Messages

Get user messages list

requires authentication supports: sorting

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/messages?sortby=date&sortdir=asc" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"filter":"all"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/messages"
);

let params = {
    "sortby": "date",
    "sortdir": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "filter": "all"
}

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 7834,
            "user_id": null,
            "message_id": 6611,
            "is_read": 0,
            "is_archived": 0,
            "is_deleted": 0,
            "message": {
                "id": 6611,
                "sender_id": null,
                "title": "Et placeat occaecati et officia consequatur repellat doloremque eos.",
                "content": "Enim quasi ab nihil eaque neque deserunt beatae.",
                "created_at": "2025-01-08T10:15:48.000000Z",
                "updated_at": "2025-01-08T10:15:48.000000Z",
                "sender": null
            }
        },
        {
            "id": 7835,
            "user_id": null,
            "message_id": 6612,
            "is_read": 0,
            "is_archived": 0,
            "is_deleted": 0,
            "message": {
                "id": 6612,
                "sender_id": null,
                "title": "Eos voluptatem consectetur sunt placeat quo et.",
                "content": "Occaecati odio eveniet vero sit consequuntur rerum quod officia.",
                "created_at": "2025-01-08T10:15:48.000000Z",
                "updated_at": "2025-01-08T10:15:48.000000Z",
                "sender": null
            }
        }
    ]
}

Request   

GET api/messages

Query Parameters

sortby  string optional  
Sort by field (available: date).

sortdir  string optional  
Sort direction (available: asc, desc).

Body Parameters

filter  string optional  
Filter results by message status (available: archived, all). Defaults to non-archived only.

Send message to multiple users

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/message" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"title":"Reminder about your vaccination","content":"Lorem ipsum dolor sit amet","roles":"Clinician,Amputee"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/message"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "title": "Reminder about your vaccination",
    "content": "Lorem ipsum dolor sit amet",
    "roles": "Clinician,Amputee"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to send messages"
}

Example response (202):

{
    "message": "Messages sent",
    "count": 3
}

Request   

POST api/message

Body Parameters

title  string  
Message title.

content  string optional  
Message content text.

roles  string optional  
Filter recipients with given role (comma-separated).

Mark message as read

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/message/10/read" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"state":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/message/10/read"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "state": 1
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (202):

{
    "id": 7836,
    "user_id": 15020,
    "message_id": 6613,
    "is_read": 0,
    "is_archived": 0,
    "is_deleted": 0
}

Request   

POST api/message/{id}/read

URL Parameters

id  integer  
User Message ID (id from messages list; do not confuse with message_id).

Body Parameters

state  integer optional  
Explicit read state. Default: 1 (true). The value must be one of 0 or 1.

Mark message as archived

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/message/10/archive" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"state":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/message/10/archive"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "state": 1
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (202):

{
    "id": 7837,
    "user_id": 15021,
    "message_id": 6614,
    "is_read": 0,
    "is_archived": 0,
    "is_deleted": 0
}

Request   

POST api/message/{id}/archive

URL Parameters

id  integer  
User Message ID (id from messages list; do not confuse with message_id).

Body Parameters

state  integer optional  
Explicit archived state. Default: 1 (true). The value must be one of 0 or 1.

List of messages and tickets

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/messages-and-tickets" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/messages-and-tickets"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 2
    },
    "items": [
        {
            "type": "UserMessage",
            "date": "2024-11-02T10:00:00.000000Z",
            "item": {
                "id": 1,
                "user_id": 1,
                "message_id": 1,
                "is_read": 0,
                "is_archived": 0,
                "is_deleted": 0,
                "message": {
                    "id": 1,
                    "sender_id": 1,
                    "title": "Message title",
                    "content": "Message content",
                    "created_at": "2024-11-02T10:00:00.000000Z",
                    "updated_at": "2024-11-02T10:00:00.000000Z",
                    "sender": {
                        "id": 1,
                        "mrn": "MRN",
                        "name": "User name",
                        "email": "user@domain.com",
                        "language": "en",
                        "phone": "",
                        "phone_verified_at": null,
                        "address1": "",
                        "address2": "",
                        "postal_code": "",
                        "city": "",
                        "clinic_name": "Test Company",
                        "clinic_location": "Test Company Location",
                        "image": null,
                        "mfa_enabled": 0,
                        "mfa_method": "email",
                        "mfa_verified_to": null,
                        "created_by": null,
                        "active": 1,
                        "notifications_timezone": "Europe\/Warsaw",
                        "notifications_at": "08:00:00",
                        "created_at": "2024-09-01T15:00:00.000000Z",
                        "updated_at": "2024-10-10T10:30:00.000000Z",
                        "invitation_status": "accepted",
                        "roles": [
                            {
                                "id": 3,
                                "name": "Clinician",
                                "guard_name": "web",
                                "created_at": "2024-01-01T12:00:00.000000Z",
                                "updated_at": "2024-01-01T12:00:00.000000Z",
                                "pivot": {
                                    "model_id": 1,
                                    "role_id": 3,
                                    "model_type": "App\\Models\\User"
                                }
                            }
                        ]
                    }
                }
            }
        },
        {
            "type": "SupportTicket",
            "date": "2024-11-01T15:15:00.000000Z",
            "item": {
                "id": 1,
                "sender_id": 1,
                "recipient_id": 999,
                "device_id": null,
                "meeting_date": "2024-11-10T15:00:00.000000Z",
                "meeting_type": "none",
                "contact_email": null,
                "status": "new",
                "created_at": "2024-11-01T15:15:00.000000Z",
                "updated_at": "2024-11-01T15:15:00.000000Z",
                "sender": {
                    "id": 1,
                    "mrn": "MRN",
                    "name": "User name",
                    "email": "user@domain.com",
                    "language": "en",
                    "phone": "",
                    "phone_verified_at": null,
                    "address1": "",
                    "address2": "",
                    "postal_code": "",
                    "city": "",
                    "clinic_name": "Test Company",
                    "clinic_location": "Test Company Location",
                    "image": null,
                    "mfa_enabled": 0,
                    "mfa_method": "email",
                    "mfa_verified_to": null,
                    "created_by": null,
                    "active": 1,
                    "notifications_timezone": "Europe\/Warsaw",
                    "notifications_at": "08:00:00",
                    "created_at": "2024-09-01T15:00:00.000000Z",
                    "updated_at": "2024-10-10T10:30:00.000000Z",
                    "invitation_status": "accepted",
                    "roles": [
                        {
                            "id": 3,
                            "name": "Clinician",
                            "guard_name": "web",
                            "created_at": "2024-01-01T12:00:00.000000Z",
                            "updated_at": "2024-01-01T12:00:00.000000Z",
                            "pivot": {
                                "model_id": 1,
                                "role_id": 3,
                                "model_type": "App\\Models\\User"
                            }
                        }
                    ]
                },
                "recipient": {
                    "id": 2,
                    "mrn": "MRN2",
                    "name": "Patient",
                    "email": "patient4@domain.com",
                    "language": "en",
                    "phone": "",
                    "phone_verified_at": null,
                    "address1": "",
                    "address2": "",
                    "postal_code": "",
                    "city": "",
                    "clinic_name": null,
                    "clinic_location": null,
                    "image": null,
                    "mfa_enabled": 0,
                    "mfa_method": null,
                    "mfa_verified_to": null,
                    "created_by": 1,
                    "active": 1,
                    "notifications_timezone": null,
                    "notifications_at": null,
                    "created_at": "2024-10-01T15:00:00.000000Z",
                    "updated_at": "2024-10-10T10:30:00.000000Z",
                    "invitation_status": null,
                    "roles": [
                        {
                            "id": 5,
                            "name": "Amputee",
                            "guard_name": "web",
                            "created_at": "2024-01-01T12:00:00.000000Z",
                            "updated_at": "2024-01-01T12:00:00.000000Z",
                            "pivot": {
                                "model_id": 2,
                                "role_id": 5,
                                "model_type": "App\\Models\\User"
                            }
                        }
                    ]
                },
                "device": null,
                "messages": [
                    {
                        "id": 1,
                        "ticket_id": 1,
                        "sender_id": 1,
                        "title": "Communication channel",
                        "content": "Welcome to the digital platform. Please use this channel for communicating with your clinician.",
                        "is_read": false,
                        "created_at": "2024-11-01T15:15:00.000000Z",
                        "updated_at": "2024-11-01T15:15:00.000000Z",
                        "attachments": [],
                        "sender": {
                            "id": 1,
                            "mrn": "MRN",
                            "name": "User name",
                            "email": "user@domain.com",
                            "language": "en",
                            "phone": "",
                            "phone_verified_at": null,
                            "address1": "",
                            "address2": "",
                            "postal_code": "",
                            "city": "",
                            "clinic_name": "Test Company",
                            "clinic_location": "Test Company Location",
                            "image": null,
                            "mfa_enabled": 0,
                            "mfa_method": "email",
                            "mfa_verified_to": null,
                            "created_by": null,
                            "active": 1,
                            "notifications_timezone": "Europe\/Warsaw",
                            "notifications_at": "08:00:00",
                            "created_at": "2024-09-01T15:00:00.000000Z",
                            "updated_at": "2024-10-10T10:30:00.000000Z",
                            "invitation_status": "accepted",
                            "roles": [
                                {
                                    "id": 3,
                                    "name": "Clinician",
                                    "guard_name": "web",
                                    "created_at": "2024-01-01T12:00:00.000000Z",
                                    "updated_at": "2024-01-01T12:00:00.000000Z",
                                    "pivot": {
                                        "model_id": 1,
                                        "role_id": 3,
                                        "model_type": "App\\Models\\User"
                                    }
                                }
                            ]
                        }
                    }
                ]
            }
        }
    ]
}

Request   

GET api/messages-and-tickets

Mobile logs

Get logs by user

requires authentication supports: extending models supports: pagination

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/logs/mobile/user/1?extend=device&perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/logs/mobile/user/1"
);

let params = {
    "extend": "device",
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view mobile logs"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 29,
            "user_id": 15109,
            "device_id": 6023,
            "content": "Culpa sapiente consequatur rerum sunt dolores inventore quae. Alias enim qui aut iure. Tenetur omnis sunt rerum eius.",
            "created_at": "2025-01-08T10:15:56.000000Z",
            "updated_at": "2025-01-08T10:15:56.000000Z"
        },
        {
            "id": 30,
            "user_id": 15110,
            "device_id": 6024,
            "content": "Vitae est suscipit et soluta voluptas. Ipsa reprehenderit voluptatibus ipsa hic qui rerum. Dolores et ex odit ipsum nulla est architecto.",
            "created_at": "2025-01-08T10:15:56.000000Z",
            "updated_at": "2025-01-08T10:15:56.000000Z"
        }
    ]
}

Request   

GET api/logs/mobile/user/{userId}

URL Parameters

userId  integer  
User ID.

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: device).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Get logs by device

requires authentication supports: pagination

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/logs/mobile/device/1?perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/logs/mobile/device/1"
);

let params = {
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view mobile logs"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 31,
            "user_id": 15111,
            "device_id": 6025,
            "content": "Est aliquam nemo provident iste. Labore excepturi minus aut sequi. Consequatur reiciendis dignissimos illum architecto deleniti aut.",
            "created_at": "2025-01-08T10:15:56.000000Z",
            "updated_at": "2025-01-08T10:15:56.000000Z"
        },
        {
            "id": 32,
            "user_id": 15112,
            "device_id": 6026,
            "content": "Enim soluta ducimus dolorum. Officiis sed quisquam est quia. Numquam quibusdam nobis temporibus consequatur earum fugiat. Tempore dignissimos et sapiente assumenda ipsum corporis.",
            "created_at": "2025-01-08T10:15:56.000000Z",
            "updated_at": "2025-01-08T10:15:56.000000Z"
        }
    ]
}

Request   

GET api/logs/mobile/device/{deviceId}

URL Parameters

deviceId  integer  
Device ID.

Query Parameters

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Store log

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/logs/mobile/store" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"device_id":1,"content":"Iste unde totam ut. Quis voluptate iste dolor aut velit. Est non quidem aperiam earum veritatis quis quas quo. Voluptatum iste magnam dolorum. Ea modi praesentium ut reprehenderit omnis nihil."}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/logs/mobile/store"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "device_id": 1,
    "content": "Iste unde totam ut. Quis voluptate iste dolor aut velit. Est non quidem aperiam earum veritatis quis quas quo. Voluptatum iste magnam dolorum. Ea modi praesentium ut reprehenderit omnis nihil."
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to write mobile logs"
}

Example response (202, Success):

{
    "id": 1,
    "length": 10000
}

Request   

POST api/logs/mobile/store

Body Parameters

device_id  string  
Device ID.

content  string  
Log content.

Append to log

requires authentication

Appends to existing log entry. Line-break character is added before appended content. Maximum size of single entry is 10000 characters. If new content is longer than this limit the beginning of content is cut off.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/logs/mobile/append/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"content":"Nam excepturi commodi vero ad libero ratione expedita. Voluptatum qui commodi neque laboriosam sed. Officiis officia perferendis dicta et modi."}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/logs/mobile/append/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "content": "Nam excepturi commodi vero ad libero ratione expedita. Voluptatum qui commodi neque laboriosam sed. Officiis officia perferendis dicta et modi."
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to write mobile logs"
}

Example response (404, Mobile log not found):

{
    "message": "Mobile log not found"
}

Example response (202, Success):

{
    "id": 1,
    "length": 10000
}

Request   

POST api/logs/mobile/append/{id}

URL Parameters

id  integer  
MobileLog ID.

Body Parameters

content  string  
Log content.

Delete log

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/logs/mobile/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/logs/mobile/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to delete mobile logs"
}

Example response (404, Mobile log not found):

{
    "message": "Mobile log not found"
}

Example response (202, Success):

{
    "message": "Mobile log entry deleted"
}

Request   

DELETE api/logs/mobile/{id}

URL Parameters

id  integer  
MobileLog ID.

P2P Sessions

Get active session data

requires authentication

Returns P2P sessions with status "waiting_for_decision" or "in_progress".

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/p2p/3/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/p2p/3/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (404, Session not found):

{
    "message": "P2P session not found"
}

Example response (200):

{
    "id": 2571,
    "amputee_id": null,
    "device_id": null,
    "clinician_id": null,
    "amputee_uuid": "ca439cfe-71bd-34a2-915a-3a2f3ea96aff",
    "clinician_uuid": "1f6e8c3f-a397-3ffe-b30b-85a66b1b6ab1",
    "token": "IZFM6IPFRMKGMM2G3CP7HU4WI5V3W97LGWDSASXQ40H2B83EHJTGDY7DCX0GHTAL",
    "status": "waiting_for_decision",
    "created_at": "2025-01-08T10:15:46.000000Z",
    "updated_at": "2025-01-08T10:15:46.000000Z"
}

Request   

GET api/p2p/{clinicianId}/{amputeeId}

URL Parameters

clinicianId  integer  
User clinician ID.

amputeeId  integer  
User amputee entry ID.

Get session data

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/p2p/3" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/p2p/3"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (404, Session not found):

{
    "message": "P2P session not found"
}

Example response (200):

{
    "id": 2572,
    "amputee_id": null,
    "device_id": null,
    "clinician_id": null,
    "amputee_uuid": "ecc92d47-d8e9-3484-9edd-e692d88892fb",
    "clinician_uuid": "9aa2aceb-b8f9-313e-8c43-bd39788065c7",
    "token": "76LTLJO2G2B63F7F3SJNUB5ZG1KDQO8KVM8WT9IOV6UQD8ZFNGPJV78RXHTX11ZJ",
    "status": "waiting_for_decision",
    "created_at": "2025-01-08T10:15:46.000000Z",
    "updated_at": "2025-01-08T10:15:46.000000Z"
}

Request   

GET api/p2p/{id}

URL Parameters

id  integer  
P2P session ID.

Create new P2P session

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/p2p/create" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"amputee_id":2,"device_id":5,"amputee_uuid":"080d6eec-c190-3449-897b-8e0210b11f64","clinician_uuid":"b7de6ecf-eb98-3927-949a-d1c825e22728"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/p2p/create"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "amputee_id": 2,
    "device_id": 5,
    "amputee_uuid": "080d6eec-c190-3449-897b-8e0210b11f64",
    "clinician_uuid": "b7de6ecf-eb98-3927-949a-d1c825e22728"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create P2P session"
}

Example response (201):

{
    "id": 2573,
    "amputee_id": 14997,
    "device_id": null,
    "clinician_id": 14998,
    "amputee_uuid": "8abc713a-0553-3dc9-8e47-8ba9b3995468",
    "clinician_uuid": "521ee09b-aade-3935-b9c9-ea901c113dc9",
    "token": "R1HA1TWDAGR5LDUS1FUUN0BKA3K0W9AYPOKY7BMHGHW110RLK85NSC16IKXBE6GR",
    "status": "waiting_for_decision",
    "created_at": "2025-01-08T10:15:46.000000Z",
    "updated_at": "2025-01-08T10:15:46.000000Z"
}

Request   

POST api/p2p/create

Body Parameters

amputee_id  string  
Amputee ID.

device_id  string  
Device ID.

amputee_uuid  string  
Amputee's UUID generated by integration platform.

clinician_uuid  string  
Clinician's UUID generated by integration platform.

Update P2P session

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/p2p/repudiandae/update" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"status":"closed"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/p2p/repudiandae/update"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "status": "closed"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update P2P session"
}

Example response (404, P2P session not found):

{
    "message": "P2P session not found"
}

Example response (200):

{
    "id": 2574,
    "amputee_id": null,
    "device_id": null,
    "clinician_id": null,
    "amputee_uuid": "d8912b6f-d421-3889-8ba3-959aaff6c353",
    "clinician_uuid": "08338c8c-50eb-3aa0-9ab1-be6623892d55",
    "token": "8AS6YPC1JIPVCFKM8DHBVHP91DERYROUWVEVAONSVMOC7LQ13OWN5Z3DHFEF90PO",
    "status": "waiting_for_decision",
    "created_at": "2025-01-08T10:15:46.000000Z",
    "updated_at": "2025-01-08T10:15:46.000000Z"
}

Request   

POST api/p2p/{id}/update

URL Parameters

id  string  

Body Parameters

status  string  
Session status. The value must be one of waiting_for_decision, in_progress, or closed.

Product features and toggles

API endpoints for product features and toggles management

Definitions:

List product features

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/product/features" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/product/features"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view product features and toggles"
}

Example response (200):

[
    {
        "id": 75,
        "name": "maroon",
        "slug": "dicta-eligendi-magnam-voluptatem-voluptatem-et-dolorem",
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    },
    {
        "id": 76,
        "name": "blue",
        "slug": "nam-sit-velit-ab-voluptates-aperiam",
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    }
]

Request   

GET api/product/features

Create product feature

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/product/features" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Remote config","slug":"remote_config"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/product/features"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Remote config",
    "slug": "remote_config"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage product features and toggles"
}

Example response (201):

{
    "id": 77,
    "name": "white",
    "slug": "architecto-et-necessitatibus-vel",
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

POST api/product/features

Body Parameters

name  string  
Name of product feature.

slug  string  
Simplified name of product feature without spaces (e.g. remote_config for Remote config name).

Update product feature

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/product/features/12" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Remote config","slug":"remote_config"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/product/features/12"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Remote config",
    "slug": "remote_config"
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage product features and toggles"
}

Example response (404, Product feature not found):

{
    "message": "Product feature not found"
}

Example response (201):

{
    "id": 78,
    "name": "olive",
    "slug": "aliquam-et-quaerat-ut-nostrum",
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

PUT api/product/features/{id}

URL Parameters

id  integer  
Product Feature ID

Body Parameters

name  string optional  
Name of product feature.

slug  string optional  
Simplified name of product feature without spaces (e.g. remote_config for Remote config name).

Delete product feature

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/product/features/8" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/product/features/8"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage product features and toggles"
}

Example response (404, Product feature not found):

{
    "message": "Product feature not found"
}

Example response (403, Product feature belongs to compatibility entries):

{
    "message": "Cannot delete: product feature belongs to existing compatibility entries (1)"
}

Example response (202):

{
    "message": "Product feature deleted"
}

Request   

DELETE api/product/features/{id}

URL Parameters

id  integer  
Product Feature ID

List product toggles

requires authentication

This endpoint returns list of global toggles. For some users there could exist user toggle which overrides these settings.

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/product/toggles?global=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/product/toggles"
);

let params = {
    "global": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view product features and toggles"
}

Example response (200):

[
    {
        "id": 82,
        "name": "blue",
        "slug": "vero-asperiores-consequatur-consequatur-debitis-nisi",
        "enabled": 1,
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    },
    {
        "id": 83,
        "name": "gray",
        "slug": "explicabo-tempora-ex-voluptas-quia-voluptatum-neque-error",
        "enabled": 0,
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    }
]

Request   

GET api/product/toggles

Query Parameters

global  integer optional  
Pass value 1 to fetch list of global toggles without user overrides.

Create product toggle

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/product/toggles" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Remote config","slug":"remote_config","enabled":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/product/toggles"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Remote config",
    "slug": "remote_config",
    "enabled": 1
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage product features and toggles"
}

Example response (201):

{
    "id": 84,
    "name": "silver",
    "slug": "earum-id-soluta-voluptas-magnam-qui-alias-dolor-voluptatem",
    "enabled": 0,
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

POST api/product/toggles

Body Parameters

name  string  
Name of product toggle.

slug  string  
Simplified name of product toggle without spaces (e.g. remote_config for Remote config name).

enabled  integer  
Is toggle enabled on this environment? The value must be one of 0 or 1.

Update product toggle

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/product/toggles/2" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Remote config","slug":"remote_config","enabled":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/product/toggles/2"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Remote config",
    "slug": "remote_config",
    "enabled": 1
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage product features and toggles"
}

Example response (404, Product toggle not found):

{
    "message": "Product toggle not found"
}

Example response (201):

{
    "id": 85,
    "name": "blue",
    "slug": "ut-aut-facilis-illum-est-et-eaque-rerum",
    "enabled": 0,
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

PUT api/product/toggles/{id}

URL Parameters

id  integer  
Product Toggle ID

Body Parameters

name  string optional  
Name of product toggle.

slug  string optional  
Simplified name of product toggle without spaces (e.g. remote_config for Remote config name).

enabled  integer optional  
Is toggle enabled on this environment? The value must be one of 0 or 1.

Delete product toggle

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/product/toggles/18" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/product/toggles/18"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage product features and toggles"
}

Example response (404, Product toggle not found):

{
    "message": "Product toggle not found"
}

Example response (202):

{
    "message": "Product toggle deleted"
}

Request   

DELETE api/product/toggles/{id}

URL Parameters

id  integer  
Product Toggle ID

List product FAQ

requires authentication supports: pagination

This endpoint returns list of product FAQ.

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/product/faq?perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/product/faq"
);

let params = {
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view product features and toggles"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 1,
            "question": "Mollitia ipsa sed commodi recusandae. Nemo doloremque sed saepe sit autem vel et et. Et occaecati molestias ducimus dolor et est. Nesciunt quia iusto earum adipisci in non soluta.",
            "answer": "Quas ullam soluta tenetur et ut dolor ipsam. Illo enim harum nam earum qui in. Vitae facere enim nesciunt sed dolor.",
            "created_at": "2025-01-08T10:15:53.000000Z",
            "updated_at": "2025-01-08T10:15:53.000000Z"
        },
        {
            "id": 2,
            "question": "Amet dolores consequatur vel soluta ut assumenda perspiciatis. Minus rem in qui. Maiores eum qui enim iusto.",
            "answer": "Et nisi sunt eum expedita. Fugit ex consequatur perferendis velit quos minima voluptates. Et in sit beatae et rerum sit.",
            "created_at": "2025-01-08T10:15:53.000000Z",
            "updated_at": "2025-01-08T10:15:53.000000Z"
        }
    ]
}

Request   

GET api/product/faq

Query Parameters

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

List user toggles

requires authentication

This endpoint returns list of user toggles with their global toggles.

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/user/19/toggles" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/19/toggles"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view product features and toggles"
}

Example response (200):

[
    {
        "id": 40,
        "toggle_id": 87,
        "user_id": 15081,
        "enabled": 1,
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z",
        "toggle": {
            "id": 87,
            "name": "teal",
            "slug": "ipsa-sint-fugiat-voluptatum-recusandae-et-pariatur-fugit",
            "enabled": 0,
            "created_at": "2025-01-08T10:15:53.000000Z",
            "updated_at": "2025-01-08T10:15:53.000000Z"
        }
    },
    {
        "id": 41,
        "toggle_id": 89,
        "user_id": 15082,
        "enabled": 0,
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z",
        "toggle": {
            "id": 89,
            "name": "olive",
            "slug": "omnis-omnis-quisquam-omnis-qui-vel-dolor",
            "enabled": 0,
            "created_at": "2025-01-08T10:15:53.000000Z",
            "updated_at": "2025-01-08T10:15:53.000000Z"
        }
    }
]

Request   

GET api/user/{userId}/toggles

URL Parameters

userId  integer  
User ID.

Create user toggle

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/17/toggles" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"toggle_id":1,"enabled":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/17/toggles"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "toggle_id": 1,
    "enabled": 1
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage product features and toggles"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (201):

{
    "id": 42,
    "toggle_id": 90,
    "user_id": 15083,
    "enabled": 1,
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

POST api/user/{userId}/toggles

URL Parameters

userId  integer  
User ID

Body Parameters

toggle_id  integer  
Product toggle ID.

enabled  integer  
Is user toggle enabled on this environment? The value must be one of 0 or 1.

Update user toggle

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/17/toggles/10" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"enabled":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/17/toggles/10"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "enabled": 1
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage product features and toggles"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (404, User toggle not found):

{
    "message": "User toggle not found"
}

Example response (201):

{
    "id": 43,
    "toggle_id": 91,
    "user_id": 15084,
    "enabled": 1,
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

PUT api/user/{userId}/toggles/{toggleId}

URL Parameters

userId  integer  
User ID

toggleId  integer  
User Toggle ID

Body Parameters

enabled  integer optional  
Is user toggle enabled on this environment? The value must be one of 0 or 1.

Delete user toggle

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/6/toggles/10" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/6/toggles/10"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to manage product features and toggles"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (404, User toggle not found):

{
    "message": "User toggle not found"
}

Example response (202):

{
    "message": "User toggle deleted"
}

Request   

DELETE api/user/{userId}/toggles/{toggleId}

URL Parameters

userId  integer  
User ID

toggleId  integer  
User Toggle ID

Releases

List releases

requires authentication supports: pagination

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/releases?perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/releases"
);

let params = {
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 58,
            "version_type": "App\\Models\\SoftwareVersion",
            "version_id": 200,
            "description": "Dolor debitis aliquid et. Eos quas laboriosam facere ut eos. Sint doloribus cumque dolores distinctio.",
            "created_at": "2025-01-08T10:15:53.000000Z",
            "updated_at": "2025-01-08T10:15:53.000000Z",
            "version": {
                "id": 200,
                "name": "0.31.37",
                "created_at": "2025-01-08T10:15:53.000000Z",
                "updated_at": "2025-01-08T10:15:53.000000Z"
            }
        },
        {
            "id": 59,
            "version_type": "App\\Models\\SoftwareVersion",
            "version_id": 201,
            "description": "Architecto earum qui minima nobis. Ut eum distinctio eligendi sed blanditiis. Ut voluptatem ut inventore quo. Expedita cumque delectus quia magni neque. Cum nihil enim eum et ut maxime.",
            "created_at": "2025-01-08T10:15:53.000000Z",
            "updated_at": "2025-01-08T10:15:53.000000Z",
            "version": {
                "id": 201,
                "name": "5.13.45",
                "created_at": "2025-01-08T10:15:53.000000Z",
                "updated_at": "2025-01-08T10:15:53.000000Z"
            }
        }
    ]
}

Request   

GET api/releases

Query Parameters

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Get release

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/releases/eos" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/releases/eos"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (404, Release not found):

{
    "message": "Release not found"
}

Example response (201):

{
    "id": 60,
    "version_type": "App\\Models\\SoftwareVersion",
    "version_id": 202,
    "description": "Id qui aut blanditiis aspernatur. Non blanditiis quas est aperiam unde deleniti. Ut est et ipsum quia quia temporibus quod. Praesentium similique consectetur incidunt alias. Vel molestiae illum odit.",
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z",
    "version": {
        "id": 202,
        "name": "7.21.50",
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    }
}

Request   

GET api/releases/{id}

URL Parameters

id  string  

Create release

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/releases" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"version_type":"SoftwareVersion","version_id":1,"description":"This version fixes minor bugs."}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/releases"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "version_type": "SoftwareVersion",
    "version_id": 1,
    "description": "This version fixes minor bugs."
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create release"
}

Example response (201):

{
    "id": 61,
    "version_type": "App\\Models\\SoftwareVersion",
    "version_id": 203,
    "description": "Autem ut tempora in saepe. Quia suscipit aut amet suscipit voluptates maxime aut quaerat. Maiores atque eos est.",
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

POST api/releases

Body Parameters

version_type  string  
Version type. The value must be one of DeviceModel, SoftwareVersion, FirmwareVersion, or PCBVersion.

version_id  integer  
Version ID.

description  string optional  
Release description.

Update release

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/releases/2" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"version_type":"SoftwareVersion","version_id":1,"description":"This version fixes minor bugs."}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/releases/2"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "version_type": "SoftwareVersion",
    "version_id": 1,
    "description": "This version fixes minor bugs."
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update release"
}

Example response (404, Release not found):

{
    "message": "Release not found"
}

Example response (201):

{
    "id": 62,
    "version_type": "App\\Models\\SoftwareVersion",
    "version_id": 204,
    "description": "Dignissimos repudiandae rerum dolor aut. Quo ea doloribus quae eligendi voluptatibus nulla.",
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

PUT api/releases/{id}

URL Parameters

id  integer  
Release ID

Body Parameters

version_type  string optional  
Version type. The value must be one of DeviceModel, SoftwareVersion, FirmwareVersion, or PCBVersion.

version_id  integer optional  
Version ID.

description  string optional  
Release description.

Delete release

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/releases/11" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/releases/11"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to delete release"
}

Example response (404, Release not found):

{
    "message": "Release not found"
}

Example response (202):

{
    "message": "Version deleted"
}

Request   

DELETE api/releases/{id}

URL Parameters

id  integer  
Release ID

Search

API endpoints for search

Search

requires authentication

Searches in:

Returned collection contains entries of type User or Device.
If the device has a patient assigned, this patient is included in the results as an entry of type User.
If the device has no patient, the device is included in the results.
Users included in the results, but not found directly have "devices" relation filled in with the devices that match the search query.

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/search" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"query":"Tom"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/search"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "query": "Tom"
}

fetch(url, {
    method: "GET",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "type": "User",
            "item": {
                "id": 1,
                "mrn": "MRN",
                "name": "User name",
                "email": "user@domain.com",
                "language": "en",
                "phone": "",
                "phone_verified_at": null,
                "address1": "",
                "address2": "",
                "postal_code": "",
                "city": "",
                "clinic_name": "Test Company",
                "clinic_location": "Test Company Location",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": "email",
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": "Europe\/Warsaw",
                "notifications_at": "08:00:00",
                "created_at": "2024-09-01T15:00:00.000000Z",
                "updated_at": "2024-10-10T10:30:00.000000Z",
                "invitation_status": "accepted",
                "pivot": {
                    "assigned_user_id": 2,
                    "user_id": 1
                },
                "devices": [],
                "roles": [
                    {
                        "id": 5,
                        "name": "Amputee",
                        "guard_name": "web",
                        "created_at": "2024-01-01T12:00:00.000000Z",
                        "updated_at": "2024-01-01T12:00:00.000000Z",
                        "pivot": {
                            "model_id": 1,
                            "role_id": 5,
                            "model_type": "App\\Models\\User"
                        }
                    }
                ]
            }
        },
        {
            "type": "Device",
            "item": {
                "id": 1,
                "serial": "SERIAL-NUMBER",
                "bluetooth_id": "BLUETOOTH_ID",
                "model_id": 1,
                "amputee_id": 1,
                "firmware_version_id": 1,
                "pcb_version_id": 1,
                "active": 1,
                "last_activity_at": "2024-11-11 12:00:00",
                "created_at": "2024-08-30T15:00:00.000000Z",
                "updated_at": "2024-09-01T16:00:00.000000Z",
                "pivot": {
                    "user_id": 2,
                    "device_id": 1
                }
            }
        }
    ]
}

Servicing

List of parts

requires authentication supports: pagination

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/servicing/parts?perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/servicing/parts"
);

let params = {
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to list service parts"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 231,
            "device_model": null,
            "name": "Visa",
            "created_at": "2025-01-08T10:15:47.000000Z",
            "updated_at": "2025-01-08T10:15:47.000000Z"
        },
        {
            "id": 232,
            "device_model": null,
            "name": "MasterCard",
            "created_at": "2025-01-08T10:15:47.000000Z",
            "updated_at": "2025-01-08T10:15:47.000000Z"
        }
    ]
}

Request   

GET api/servicing/parts

Query Parameters

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Report service repair

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/servicing/repair" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: multipart/form-data" \
    -H "Accept: application/json" \
    -F "user_id=1" \
    -F "device_id=1" \
    -F "parts[][part_id]=1" \
    -F "parts[][reason]=Mechanical issue" \
    -F "files[]=@/tmp/phpX76e01" 
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/servicing/repair"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "multipart/form-data",
    "Accept": "application/json",
};

const body = new FormData();
body.append('user_id', '1');
body.append('device_id', '1');
body.append('parts[][part_id]', '1');
body.append('parts[][reason]', 'Mechanical issue');
body.append('files[]', document.querySelector('input[name="files[]"]').files[0]);

fetch(url, {
    method: "POST",
    headers,
    body,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to report service repair"
}

Example response (201):

{
    "id": 103,
    "user_id": 15015,
    "device_id": 5993,
    "created_at": "2025-01-08T10:15:47.000000Z",
    "updated_at": "2025-01-08T10:15:47.000000Z",
    "parts": [
        {
            "id": 95,
            "repair_id": 103,
            "part_id": 233,
            "reason": "Suscipit a eos sequi et ut nihil. Repellendus rerum nihil in autem perferendis. Molestiae voluptatem est non aliquid quis sed.",
            "created_at": "2025-01-08T10:15:47.000000Z",
            "updated_at": "2025-01-08T10:15:47.000000Z",
            "part": {
                "id": 233,
                "device_model": null,
                "name": "MasterCard",
                "created_at": "2025-01-08T10:15:47.000000Z",
                "updated_at": "2025-01-08T10:15:47.000000Z"
            }
        },
        {
            "id": 96,
            "repair_id": 103,
            "part_id": 234,
            "reason": "Exercitationem soluta deleniti at possimus quae laborum eius. Veniam aut doloribus nihil aspernatur. Recusandae illo in et eos est.",
            "created_at": "2025-01-08T10:15:47.000000Z",
            "updated_at": "2025-01-08T10:15:47.000000Z",
            "part": {
                "id": 234,
                "device_model": null,
                "name": "Visa Retired",
                "created_at": "2025-01-08T10:15:47.000000Z",
                "updated_at": "2025-01-08T10:15:47.000000Z"
            }
        }
    ],
    "attachments": [
        {
            "id": 107,
            "repair_id": 103,
            "file": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerxo2jV3",
            "created_at": "2025-01-08T10:15:48.000000Z",
            "updated_at": "2025-01-08T10:15:48.000000Z"
        },
        {
            "id": 108,
            "repair_id": 103,
            "file": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerbVhMgk",
            "created_at": "2025-01-08T10:15:48.000000Z",
            "updated_at": "2025-01-08T10:15:48.000000Z"
        }
    ]
}

Request   

POST api/servicing/repair

Body Parameters

user_id  integer  
User ID.

device_id  integer  
Device ID.

files  file[] optional  
Array of attachment files.

parts  object[] optional  
Array of replaced parts.

parts[].part_id  integer optional  
Service part ID.

parts[].reason  string optional  
Reason of part replacement.

Settings

Get app version

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/settings/app-version" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/settings/app-version"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "version": "1.6.0"
}

Request   

GET api/settings/app-version

Get silent push timeout

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/settings/silent-push" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/settings/silent-push"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "timeout": "15"
}

Request   

GET api/settings/silent-push

Get available languages

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/settings/languages" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/settings/languages"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "languages": [
        "de",
        "en",
        "es",
        "it",
        "pl",
        "ru",
        "uk"
    ]
}

Request   

GET api/settings/languages

Get mobile stores versions

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/mobile/versions" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/mobile/versions"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "ios": "1.0",
    "android": "1.0"
}

Request   

GET api/mobile/versions

Update app version

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/settings/app-version" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"version":"1.6.0"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/settings/app-version"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "version": "1.6.0"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update settings"
}

Example response (200):

{
    "version": "1.6.0"
}

Request   

POST api/settings/app-version

Body Parameters

version  string optional  
App version.

Update silent push timeout

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/settings/silent-push" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"timeout":15}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/settings/silent-push"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "timeout": 15
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update settings"
}

Example response (200):

{
    "timeout": "15"
}

Request   

POST api/settings/silent-push

Body Parameters

timeout  integer optional  
Silent push timeout in minutes. Minimum value is 1 minute (15 for production environment), maximum is 60 minutes.

Update mobile stores versions

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/mobile/versions" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"ios":"1.1","android":"1.1"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/mobile/versions"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "ios": "1.1",
    "android": "1.1"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update settings"
}

Example response (200):

{
    "ios": "1.0",
    "android": "1.0"
}

Request   

POST api/mobile/versions

Body Parameters

ios  string optional  
Apple AppStore current version.

android  string optional  
Google Play current version.

Support Ticket

Get tickets list

requires authentication supports: extending models supports: pagination supports: sorting

Possible extend options:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/tickets?status=sit&sender=12&recipient=12&device=1&extend=sender%2C+recipient%2C+device%2C+messages%2C+messages.attachments&perpage=20&page=1&sortby=sender_name%2C+recipient_name%2C+date%2C+last_message&sortdir=asc" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/tickets"
);

let params = {
    "status": "sit",
    "sender": "12",
    "recipient": "12",
    "device": "1",
    "extend": "sender, recipient, device, messages, messages.attachments",
    "perpage": "20",
    "page": "1",
    "sortby": "sender_name, recipient_name, date, last_message",
    "sortdir": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to list support tickets"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 4440,
            "sender_id": 15024,
            "recipient_id": 15025,
            "device_id": 5999,
            "meeting_date": "2025-01-08T10:15:48.000000Z",
            "meeting_type": "online_meeting",
            "contact_email": "lakin.alyson@funk.info",
            "status": "new",
            "created_at": "2025-01-08T10:15:48.000000Z",
            "updated_at": "2025-01-08T10:15:48.000000Z",
            "sender": {
                "id": 15024,
                "mrn": "CO3BBAEX",
                "name": "Alia Osinski DDS",
                "email": "1736331348doyle.dolly@example.net",
                "language": "en",
                "phone": "281-246-0969",
                "phone_country": "BN",
                "phone_verified_at": null,
                "address1": "33156 Larue Loaf",
                "address2": "New Avismouth, DC 34639",
                "postal_code": "91642-4921",
                "city": "Wolf-Corkery",
                "clinic_name": "South Krystal",
                "clinic_location": "29108 Daphney Corner\nEast Ardenborough, MN 85519-8453",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:48.000000Z",
                "updated_at": "2025-01-08T10:15:48.000000Z",
                "invitation_status": null,
                "roles": []
            },
            "recipient": {
                "id": 15025,
                "mrn": "L5DJKZHB",
                "name": "Ivy Little",
                "email": "1736331348cmurphy@example.org",
                "language": "en",
                "phone": "+1 (915) 297-6353",
                "phone_country": "UA",
                "phone_verified_at": null,
                "address1": "16728 Fred Isle",
                "address2": "East Madilynborough, TX 57894",
                "postal_code": "25445",
                "city": "Rolfson-Senger",
                "clinic_name": "East Francescoport",
                "clinic_location": "878 Stokes Gateway Apt. 776\nLake Elnora, UT 58411-6256",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:48.000000Z",
                "updated_at": "2025-01-08T10:15:48.000000Z",
                "invitation_status": null,
                "roles": []
            },
            "device": {
                "id": 5999,
                "serial": "b3278913-bb19-3f4e-8342-4ba018ae1140",
                "bluetooth_id": "a4763bc7-6f1a-308e-94ad-d235e8390b86",
                "model_id": null,
                "amputee_id": null,
                "firmware_version_id": null,
                "pcb_version_id": null,
                "active": 1,
                "last_activity_at": "0000-00-00 00:00:00",
                "created_at": "2025-01-08T10:15:48.000000Z",
                "updated_at": "2025-01-08T10:15:48.000000Z"
            },
            "messages": [
                {
                    "id": 4538,
                    "ticket_id": 4440,
                    "sender_id": 15026,
                    "title": "Ms.",
                    "content": "Debitis sint et voluptates atque exercitationem blanditiis et corporis.",
                    "is_read": false,
                    "created_at": "2025-01-08T10:15:48.000000Z",
                    "updated_at": "2025-01-08T10:15:48.000000Z",
                    "attachments": [
                        {
                            "id": 6579,
                            "ticket_id": 4440,
                            "ticket_message_id": 4538,
                            "type": "application\/vnd.sema",
                            "title": "Cordell Effertz",
                            "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/005577%3Ftext%3Dquibusdam",
                            "created_at": "2025-01-08T10:15:48.000000Z",
                            "updated_at": "2025-01-08T10:15:48.000000Z"
                        },
                        {
                            "id": 6580,
                            "ticket_id": 4440,
                            "ticket_message_id": 4538,
                            "type": "application\/vnd.wap.wbxml",
                            "title": "Clement Carter Sr.",
                            "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/0000bb%3Ftext%3Dpraesentium",
                            "created_at": "2025-01-08T10:15:48.000000Z",
                            "updated_at": "2025-01-08T10:15:48.000000Z"
                        },
                        {
                            "id": 6581,
                            "ticket_id": 4440,
                            "ticket_message_id": 4538,
                            "type": "video\/h263",
                            "title": "Maribel Reynolds V",
                            "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/00bb00%3Ftext%3Dlaudantium",
                            "created_at": "2025-01-08T10:15:48.000000Z",
                            "updated_at": "2025-01-08T10:15:48.000000Z"
                        }
                    ],
                    "sender": {
                        "id": 15026,
                        "mrn": "H0UDXUWQ",
                        "name": "Alysson Weber",
                        "email": "1736331348garnett.barton@example.com",
                        "language": "en",
                        "phone": "689.821.4219",
                        "phone_country": "UY",
                        "phone_verified_at": null,
                        "address1": "840 Zackary Shore",
                        "address2": "Jacobistad, LA 08526-8030",
                        "postal_code": "57478-4462",
                        "city": "Farrell-Kub",
                        "clinic_name": "Port Mayra",
                        "clinic_location": "79933 Caesar Forest\nLake Johnpaul, TX 46224-8653",
                        "image": null,
                        "mfa_enabled": 0,
                        "mfa_method": null,
                        "mfa_verified_to": null,
                        "created_by": null,
                        "active": 1,
                        "notifications_timezone": null,
                        "notifications_at": null,
                        "created_at": "2025-01-08T10:15:48.000000Z",
                        "updated_at": "2025-01-08T10:15:48.000000Z",
                        "invitation_status": null,
                        "roles": []
                    }
                }
            ]
        },
        {
            "id": 4441,
            "sender_id": 15030,
            "recipient_id": 15031,
            "device_id": 6001,
            "meeting_date": "2025-01-08T10:15:48.000000Z",
            "meeting_type": "online_meeting",
            "contact_email": "zolson@frami.com",
            "status": "new",
            "created_at": "2025-01-08T10:15:49.000000Z",
            "updated_at": "2025-01-08T10:15:49.000000Z",
            "sender": {
                "id": 15030,
                "mrn": "KBQR5UQC",
                "name": "Mrs. Sarai Labadie",
                "email": "1736331348jast.clarissa@example.com",
                "language": "en",
                "phone": "+1-949-261-0653",
                "phone_country": "TT",
                "phone_verified_at": null,
                "address1": "66111 Marcos Meadow Apt. 753",
                "address2": "Felipaside, NV 97458-4164",
                "postal_code": "30458",
                "city": "Von Group",
                "clinic_name": "New Dimitrishire",
                "clinic_location": "81732 Volkman Spring\nBoehmside, MD 74452-7586",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:49.000000Z",
                "updated_at": "2025-01-08T10:15:49.000000Z",
                "invitation_status": null,
                "roles": []
            },
            "recipient": {
                "id": 15031,
                "mrn": "XMEFIZNM",
                "name": "Dr. Glenna Adams",
                "email": "1736331349kaycee.schamberger@example.org",
                "language": "en",
                "phone": "+1.631.543.2698",
                "phone_country": "IL",
                "phone_verified_at": null,
                "address1": "2477 Bayer Knolls Suite 526",
                "address2": "Kalebmouth, WV 10632-6505",
                "postal_code": "81770",
                "city": "Berge-Mueller",
                "clinic_name": "Jastfort",
                "clinic_location": "83818 Samir Parkway Suite 242\nNorth Jesseland, IA 13389-9778",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:49.000000Z",
                "updated_at": "2025-01-08T10:15:49.000000Z",
                "invitation_status": null,
                "roles": []
            },
            "device": {
                "id": 6001,
                "serial": "ae5d9b7e-675d-35f3-b690-f58a163bda57",
                "bluetooth_id": "265fb788-c5aa-3938-a95a-440cac1ee6ff",
                "model_id": null,
                "amputee_id": null,
                "firmware_version_id": null,
                "pcb_version_id": null,
                "active": 1,
                "last_activity_at": "0000-00-00 00:00:00",
                "created_at": "2025-01-08T10:15:49.000000Z",
                "updated_at": "2025-01-08T10:15:49.000000Z"
            },
            "messages": [
                {
                    "id": 4539,
                    "ticket_id": 4441,
                    "sender_id": 15032,
                    "title": "Miss",
                    "content": "Adipisci harum et quae est eveniet.",
                    "is_read": false,
                    "created_at": "2025-01-08T10:15:49.000000Z",
                    "updated_at": "2025-01-08T10:15:49.000000Z",
                    "attachments": [
                        {
                            "id": 6582,
                            "ticket_id": 4441,
                            "ticket_message_id": 4539,
                            "type": "text\/vnd.curl.scurl",
                            "title": "Stephanie Kozey",
                            "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/00bbbb%3Ftext%3Dlaboriosam",
                            "created_at": "2025-01-08T10:15:49.000000Z",
                            "updated_at": "2025-01-08T10:15:49.000000Z"
                        },
                        {
                            "id": 6583,
                            "ticket_id": 4441,
                            "ticket_message_id": 4539,
                            "type": "application\/x-xpinstall",
                            "title": "Mrs. Dana Kuvalis",
                            "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/001188%3Ftext%3Dquia",
                            "created_at": "2025-01-08T10:15:49.000000Z",
                            "updated_at": "2025-01-08T10:15:49.000000Z"
                        },
                        {
                            "id": 6584,
                            "ticket_id": 4441,
                            "ticket_message_id": 4539,
                            "type": "audio\/x-aac",
                            "title": "Esther Moen",
                            "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/004488%3Ftext%3Ddolorem",
                            "created_at": "2025-01-08T10:15:49.000000Z",
                            "updated_at": "2025-01-08T10:15:49.000000Z"
                        }
                    ],
                    "sender": {
                        "id": 15032,
                        "mrn": "U7XDVZ4L",
                        "name": "Prof. Priscilla Mohr DDS",
                        "email": "1736331349birdie11@example.org",
                        "language": "en",
                        "phone": "786-918-1662",
                        "phone_country": "SH",
                        "phone_verified_at": null,
                        "address1": "381 Domenic Pike",
                        "address2": "New Diamond, MS 12360",
                        "postal_code": "43298-9685",
                        "city": "Dach PLC",
                        "clinic_name": "Pacochaland",
                        "clinic_location": "63162 Cronin Courts\nNew Ettie, NY 26840",
                        "image": null,
                        "mfa_enabled": 0,
                        "mfa_method": null,
                        "mfa_verified_to": null,
                        "created_by": null,
                        "active": 1,
                        "notifications_timezone": null,
                        "notifications_at": null,
                        "created_at": "2025-01-08T10:15:49.000000Z",
                        "updated_at": "2025-01-08T10:15:49.000000Z",
                        "invitation_status": null,
                        "roles": []
                    }
                }
            ]
        }
    ]
}

Request   

GET api/tickets

Query Parameters

status  string optional  
Filter tickets by status (available: new,in_progress,closed,reopened).

sender  integer optional  
Filter tickets by sender.

recipient  integer optional  
Filter tickets by recipient.

device  integer optional  
Filter tickets by device.

extend  string optional  
Comma-separated list of relation extensions (available: sender, recipient, device, messages, messages.attachments).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

sortby  string optional  
Sort by field (available: sender_name, recipient_name, date, last_message).

sortdir  string optional  
Sort direction (available: asc, desc).

Get tickets status

requires authentication

Counts tickets by their status

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/tickets/status" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/tickets/status"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "unread": 1
}

Request   

GET api/tickets/status

Get support ticket

requires authentication supports: extending models

Returns single support ticket in response

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/ticket/3?extend=sender%2C+recipient%2C+device%2C+messages%2C+messages.attachments%2C+messages.sender" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/ticket/3"
);

let params = {
    "extend": "sender, recipient, device, messages, messages.attachments, messages.sender",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view support ticket"
}

Example response (404, Support ticket not found):

{
    "message": "Support ticket not found"
}

Example response (200):

{
    "id": 4442,
    "sender_id": 15036,
    "recipient_id": 15037,
    "device_id": 6003,
    "meeting_date": "2025-01-08T10:15:49.000000Z",
    "meeting_type": "online_meeting",
    "contact_email": "mosciski.walker@rodriguez.org",
    "status": "new",
    "created_at": "2025-01-08T10:15:49.000000Z",
    "updated_at": "2025-01-08T10:15:49.000000Z",
    "sender": {
        "id": 15036,
        "mrn": "HBWY4ZIL",
        "name": "Maria Hackett",
        "email": "1736331349theller@example.org",
        "language": "en",
        "phone": "+1 (952) 815-8485",
        "phone_country": "FM",
        "phone_verified_at": null,
        "address1": "178 Toney Walks Suite 196",
        "address2": "North Iliana, ID 87312",
        "postal_code": "29535-2830",
        "city": "Fay-Daugherty",
        "clinic_name": "Braulioview",
        "clinic_location": "8459 Williamson Meadow Suite 715\nWest Concepcion, MA 14049-7604",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:49.000000Z",
        "updated_at": "2025-01-08T10:15:49.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "recipient": {
        "id": 15037,
        "mrn": "ZVL7Z4TO",
        "name": "Ms. Julie Klocko V",
        "email": "1736331349angeline.cruickshank@example.org",
        "language": "en",
        "phone": "+1 (904) 704-4090",
        "phone_country": "LA",
        "phone_verified_at": null,
        "address1": "18731 Joanne Creek",
        "address2": "Wilkinsonview, IA 79971-5731",
        "postal_code": "39140-5300",
        "city": "Aufderhar-Swaniawski",
        "clinic_name": "New Tracyville",
        "clinic_location": "48012 Moore Summit Suite 853\nJarrettshire, MI 52232-9846",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:49.000000Z",
        "updated_at": "2025-01-08T10:15:49.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "device": {
        "id": 6003,
        "serial": "ef13fc11-445c-3826-9f79-07df33a52300",
        "bluetooth_id": "7fa9354a-1039-38bc-b32f-3e27b3814c1f",
        "model_id": null,
        "amputee_id": null,
        "firmware_version_id": null,
        "pcb_version_id": null,
        "active": 1,
        "last_activity_at": "0000-00-00 00:00:00",
        "created_at": "2025-01-08T10:15:49.000000Z",
        "updated_at": "2025-01-08T10:15:49.000000Z"
    },
    "messages": [
        {
            "id": 4540,
            "ticket_id": 4442,
            "sender_id": 15038,
            "title": "Miss",
            "content": "Temporibus est et eligendi doloremque quia iusto.",
            "is_read": false,
            "created_at": "2025-01-08T10:15:49.000000Z",
            "updated_at": "2025-01-08T10:15:49.000000Z",
            "attachments": [
                {
                    "id": 6585,
                    "ticket_id": 4442,
                    "ticket_message_id": 4540,
                    "type": "application\/vnd.openofficeorg.extension",
                    "title": "Karine Kovacek",
                    "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/001155%3Ftext%3Domnis",
                    "created_at": "2025-01-08T10:15:49.000000Z",
                    "updated_at": "2025-01-08T10:15:49.000000Z"
                },
                {
                    "id": 6586,
                    "ticket_id": 4442,
                    "ticket_message_id": 4540,
                    "type": "application\/vnd.adobe.xdp+xml",
                    "title": "Rex Fay IV",
                    "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/00aa11%3Ftext%3Dnisi",
                    "created_at": "2025-01-08T10:15:49.000000Z",
                    "updated_at": "2025-01-08T10:15:49.000000Z"
                },
                {
                    "id": 6587,
                    "ticket_id": 4442,
                    "ticket_message_id": 4540,
                    "type": "text\/x-setext",
                    "title": "Mae Daniel",
                    "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/0000ee%3Ftext%3Dvoluptate",
                    "created_at": "2025-01-08T10:15:49.000000Z",
                    "updated_at": "2025-01-08T10:15:49.000000Z"
                }
            ],
            "sender": {
                "id": 15038,
                "mrn": "6M05T65F",
                "name": "Soledad Schumm",
                "email": "1736331349wpurdy@example.net",
                "language": "en",
                "phone": "(848) 476-7118",
                "phone_country": "MS",
                "phone_verified_at": null,
                "address1": "755 Viva Lodge Apt. 131",
                "address2": "South Estrellaside, IN 78695-0476",
                "postal_code": "56103",
                "city": "Adams Group",
                "clinic_name": "Lake Albertha",
                "clinic_location": "712 Kerluke Plains\nHeathcotemouth, OK 66364",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:49.000000Z",
                "updated_at": "2025-01-08T10:15:49.000000Z",
                "invitation_status": null,
                "roles": []
            }
        }
    ]
}

Request   

GET api/ticket/{id}

URL Parameters

id  integer  
Ticket ID.

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: sender, recipient, device, messages, messages.attachments, messages.sender).

Get support ticket history

requires authentication supports: pagination supports: sorting

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/ticket/3/history?perpage=20&page=1&sortby=date&sortdir=asc" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/ticket/3/history"
);

let params = {
    "perpage": "20",
    "page": "1",
    "sortby": "date",
    "sortdir": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view support ticket"
}

Example response (404, Support ticket not found):

{
    "message": "Support ticket not found"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 3725,
            "ticket_id": 4443,
            "author_id": 15042,
            "action": "qui",
            "reason": "Perspiciatis nesciunt ipsam fugiat corrupti sed.",
            "created_at": "2025-01-08T10:15:49.000000Z",
            "updated_at": "2025-01-08T10:15:49.000000Z"
        },
        {
            "id": 3726,
            "ticket_id": 4444,
            "author_id": 15045,
            "action": "beatae",
            "reason": "Voluptate reprehenderit optio est ullam et.",
            "created_at": "2025-01-08T10:15:50.000000Z",
            "updated_at": "2025-01-08T10:15:50.000000Z"
        }
    ]
}

Request   

GET api/ticket/{id}/history

URL Parameters

id  integer  
Ticket ID.

Query Parameters

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

sortby  string optional  
Sort by field (available: date). Default: date (desc).

sortdir  string optional  
Sort direction (available: asc, desc).

Get support ticket available filters

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/tickets/available-filters" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/tickets/available-filters"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200, Filters):

{
    "clinicians": [
        {
            "id": 95,
            "mrn": null,
            "name": "Name",
            "email": "email",
            "region": "us",
            "language": "pl",
            "phone": "+48-555555555",
            "phone_verified_at": null,
            "address1": "Address",
            "address2": "Address 2",
            "postal_code": "",
            "city": "",
            "clinic_name": "Name",
            "clinic_location": "Name",
            "image": "https:\/\/aether-dev-bucket.s3.amazonaws.com\/users\/LDueuv1uG218G7owaiLAaWRkpaGxjB0jEFwzZsT1.png",
            "mfa_enabled": 0,
            "mfa_method": "sms",
            "mfa_verified_to": null,
            "location_id": 2,
            "created_by": 1,
            "active": 1,
            "notifications_timezone": "America\/Adak",
            "notifications_at": null,
            "created_at": "2022-07-19T14:43:37.000000Z",
            "updated_at": "2024-09-27T05:52:51.000000Z",
            "invitation_status": "expired",
            "roles": [
                {
                    "id": 2,
                    "name": "Clinician",
                    "guard_name": "web",
                    "created_at": "2022-03-21T17:15:47.000000Z",
                    "updated_at": "2022-03-21T17:15:47.000000Z",
                    "pivot": {
                        "model_id": 95,
                        "role_id": 2,
                        "model_type": "App\\Models\\User"
                    }
                }
            ]
        }
    ]
}

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view support ticket"
}

Example response (200):

{
    "data": [
        {
            "id": 4445,
            "sender_id": 15046,
            "recipient_id": 15047,
            "device_id": 6006,
            "meeting_date": "2025-01-08T10:15:50.000000Z",
            "meeting_type": "online_meeting",
            "contact_email": "zoey.bruen@hotmail.com",
            "status": "new",
            "created_at": "2025-01-08T10:15:50.000000Z",
            "updated_at": "2025-01-08T10:15:50.000000Z"
        },
        {
            "id": 4446,
            "sender_id": 15048,
            "recipient_id": 15049,
            "device_id": 6007,
            "meeting_date": "2025-01-08T10:15:50.000000Z",
            "meeting_type": "online_meeting",
            "contact_email": "katheryn83@hotmail.com",
            "status": "new",
            "created_at": "2025-01-08T10:15:50.000000Z",
            "updated_at": "2025-01-08T10:15:50.000000Z"
        }
    ]
}

Request   

GET api/tickets/available-filters

Create new support ticket

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/tickets" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d ''
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/tickets"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = 

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create support ticket"
}

Example response (201):

{
    "id": 4447,
    "sender_id": 15052,
    "recipient_id": 15053,
    "device_id": 6009,
    "meeting_date": "2025-01-08T10:15:50.000000Z",
    "meeting_type": "online_meeting",
    "contact_email": "koss.precious@lang.net",
    "status": "new",
    "created_at": "2025-01-08T10:15:50.000000Z",
    "updated_at": "2025-01-08T10:15:50.000000Z",
    "sender": {
        "id": 15052,
        "mrn": "B0R1RVYP",
        "name": "Mr. Cecil Brekke",
        "email": "1736331350aron.robel@example.org",
        "language": "en",
        "phone": "(269) 558-7521",
        "phone_country": "GB",
        "phone_verified_at": null,
        "address1": "7251 Metz Radial Apt. 171",
        "address2": "West Juwanborough, NJ 99949-7304",
        "postal_code": "33388-8631",
        "city": "Nicolas-Mayert",
        "clinic_name": "Zaneborough",
        "clinic_location": "529 Elody Glen\nGaylordtown, CA 34300",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:50.000000Z",
        "updated_at": "2025-01-08T10:15:50.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "recipient": {
        "id": 15053,
        "mrn": "YDHED97W",
        "name": "Marley Ullrich Sr.",
        "email": "1736331350akautzer@example.net",
        "language": "en",
        "phone": "(386) 415-5681",
        "phone_country": "SH",
        "phone_verified_at": null,
        "address1": "58674 Manuela Land",
        "address2": "South Ricardo, MN 02024-6037",
        "postal_code": "31253",
        "city": "Dooley-O'Hara",
        "clinic_name": "Blickstad",
        "clinic_location": "129 River Land Apt. 747\nLake Verdaton, NY 93788",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:50.000000Z",
        "updated_at": "2025-01-08T10:15:50.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "device": {
        "id": 6009,
        "serial": "59e5c21c-2790-3250-9762-908b62ebd1c8",
        "bluetooth_id": "d6255726-b1cb-3357-a053-5db175890598",
        "model_id": null,
        "amputee_id": null,
        "firmware_version_id": null,
        "pcb_version_id": null,
        "active": 1,
        "last_activity_at": "0000-00-00 00:00:00",
        "created_at": "2025-01-08T10:15:50.000000Z",
        "updated_at": "2025-01-08T10:15:50.000000Z"
    },
    "messages": [
        {
            "id": 4541,
            "ticket_id": 4447,
            "sender_id": 15054,
            "title": "Prof.",
            "content": "Autem voluptas esse eos cupiditate.",
            "is_read": false,
            "created_at": "2025-01-08T10:15:51.000000Z",
            "updated_at": "2025-01-08T10:15:51.000000Z",
            "attachments": [
                {
                    "id": 6588,
                    "ticket_id": 4447,
                    "ticket_message_id": 4541,
                    "type": "application\/x-ustar",
                    "title": "Dr. Ahmad Walker IV",
                    "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/000011%3Ftext%3Dquibusdam",
                    "created_at": "2025-01-08T10:15:51.000000Z",
                    "updated_at": "2025-01-08T10:15:51.000000Z"
                },
                {
                    "id": 6589,
                    "ticket_id": 4447,
                    "ticket_message_id": 4541,
                    "type": "application\/vnd.llamagraphics.life-balance.desktop",
                    "title": "Twila Senger",
                    "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/007744%3Ftext%3Dvoluptatem",
                    "created_at": "2025-01-08T10:15:51.000000Z",
                    "updated_at": "2025-01-08T10:15:51.000000Z"
                },
                {
                    "id": 6590,
                    "ticket_id": 4447,
                    "ticket_message_id": 4541,
                    "type": "text\/vnd.in3d.3dml",
                    "title": "Mylene Gutkowski V",
                    "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/00ee00%3Ftext%3Det",
                    "created_at": "2025-01-08T10:15:51.000000Z",
                    "updated_at": "2025-01-08T10:15:51.000000Z"
                }
            ],
            "sender": {
                "id": 15054,
                "mrn": "VSLN9EW7",
                "name": "Dr. Alejandrin Hoeger V",
                "email": "1736331350hardy.keeling@example.org",
                "language": "en",
                "phone": "754.602.4662",
                "phone_country": "CY",
                "phone_verified_at": null,
                "address1": "8849 Luther Fords",
                "address2": "Crooksburgh, AZ 23152-5615",
                "postal_code": "05351",
                "city": "Rempel and Sons",
                "clinic_name": "Lake Julesberg",
                "clinic_location": "9234 Wisozk Underpass Apt. 379\nJadefort, MT 36065",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:50.000000Z",
                "updated_at": "2025-01-08T10:15:50.000000Z",
                "invitation_status": null,
                "roles": []
            }
        }
    ]
}

Request   

POST api/tickets

Body Parameters

recipient  integer  
User the support ticket is assigned to. For Amputee role main clinician will be automatically assigned instead.

device  integer optional  
Device the support ticket is assigned to.

meeting_type  string  
Type of support meeting The value must be one of online_meeting, phone_call, personally, or none.

meeting_date  string  
Date of support meeting The value must be a valid date.

contact_email  string optional  
Email address for later contact The value must be a valid email address.

message  object optional  

message.content  string optional  
Content of message.

message.title  string optional  
Message title.

message.attachments  file[] optional  
The value must be a file.

Close support ticket

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/ticket/3/close" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/ticket/3/close"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to close support ticket"
}

Example response (404, Support ticket not found):

{
    "message": "Support ticket not found"
}

Example response (202):

{
    "id": 4448,
    "sender_id": 15058,
    "recipient_id": 15059,
    "device_id": 6011,
    "meeting_date": "2025-01-08T10:15:51.000000Z",
    "meeting_type": "online_meeting",
    "contact_email": "dillon88@damore.com",
    "status": "new",
    "created_at": "2025-01-08T10:15:51.000000Z",
    "updated_at": "2025-01-08T10:15:51.000000Z"
}

Request   

POST api/ticket/{id}/close

URL Parameters

id  integer  
Support ticket ID.

Reopen support ticket

requires authentication

Patient (Amputee) role can reopen only non-config tickets. For config tickets patients will get "Insufficient permission" response. For patients role reason field is required.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/ticket/3/reopen" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"reason":"Something is still not working"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/ticket/3/reopen"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "reason": "Something is still not working"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to reopen support ticket"
}

Example response (404, Support ticket not found):

{
    "message": "Support ticket not found"
}

Example response (202):

{
    "id": 3727,
    "ticket_id": 4449,
    "author_id": 15062,
    "action": "atque",
    "reason": "Fugiat hic est deleniti.",
    "created_at": "2025-01-08T10:15:51.000000Z",
    "updated_at": "2025-01-08T10:15:51.000000Z"
}

Request   

POST api/ticket/{id}/reopen

URL Parameters

id  integer  
Support ticket ID.

Body Parameters

reason  string optional  
Reason for reopen action.

Create new support ticket message

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/ticket/minus/messages" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: multipart/form-data" \
    -H "Accept: application/json" \
    -F "title=Reprehenderit iste eveniet nisi." \
    -F "content=Dolorem veritatis distinctio enim eos eaque laudantium ab." \
    -F "attachments[]=@/tmp/phpKmjqQB" 
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/ticket/minus/messages"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "multipart/form-data",
    "Accept": "application/json",
};

const body = new FormData();
body.append('title', 'Reprehenderit iste eveniet nisi.');
body.append('content', 'Dolorem veritatis distinctio enim eos eaque laudantium ab.');
body.append('attachments[]', document.querySelector('input[name="attachments[]"]').files[0]);

fetch(url, {
    method: "POST",
    headers,
    body,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create support ticket"
}

Example response (201):

{
    "id": 4450,
    "sender_id": 15065,
    "recipient_id": 15066,
    "device_id": 6014,
    "meeting_date": "2025-01-08T10:15:51.000000Z",
    "meeting_type": "online_meeting",
    "contact_email": "yschmitt@hermiston.org",
    "status": "new",
    "created_at": "2025-01-08T10:15:51.000000Z",
    "updated_at": "2025-01-08T10:15:51.000000Z",
    "sender": {
        "id": 15065,
        "mrn": "XSRJZGZT",
        "name": "Laury Zieme III",
        "email": "1736331351keebler.modesta@example.com",
        "language": "en",
        "phone": "+12486619657",
        "phone_country": "ER",
        "phone_verified_at": null,
        "address1": "4943 Raquel Plaza Apt. 312",
        "address2": "Pfannerstillville, CO 42268",
        "postal_code": "33812-2776",
        "city": "Funk LLC",
        "clinic_name": "New Michellemouth",
        "clinic_location": "4839 Runolfsson Streets\nSouth Kaelynton, WA 45014-1919",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:51.000000Z",
        "updated_at": "2025-01-08T10:15:51.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "recipient": {
        "id": 15066,
        "mrn": "3ED8B0EX",
        "name": "Candace King",
        "email": "1736331351zrolfson@example.org",
        "language": "en",
        "phone": "1-850-607-3713",
        "phone_country": "CU",
        "phone_verified_at": null,
        "address1": "465 Aditya Estates Suite 057",
        "address2": "South Ewell, MT 89560-1150",
        "postal_code": "95326",
        "city": "Boyle PLC",
        "clinic_name": "Port Nedraton",
        "clinic_location": "984 Nienow Crest\nWisokyborough, PA 67532",
        "image": null,
        "mfa_enabled": 0,
        "mfa_method": null,
        "mfa_verified_to": null,
        "created_by": null,
        "active": 1,
        "notifications_timezone": null,
        "notifications_at": null,
        "created_at": "2025-01-08T10:15:51.000000Z",
        "updated_at": "2025-01-08T10:15:51.000000Z",
        "invitation_status": null,
        "roles": []
    },
    "device": {
        "id": 6014,
        "serial": "b742050f-a141-32da-a8ee-b828cba7eb20",
        "bluetooth_id": "6af1a96e-ca82-34e1-ac09-2a852a860f1f",
        "model_id": null,
        "amputee_id": null,
        "firmware_version_id": null,
        "pcb_version_id": null,
        "active": 1,
        "last_activity_at": "0000-00-00 00:00:00",
        "created_at": "2025-01-08T10:15:51.000000Z",
        "updated_at": "2025-01-08T10:15:51.000000Z"
    },
    "messages": [
        {
            "id": 4542,
            "ticket_id": 4450,
            "sender_id": 15067,
            "title": "Ms.",
            "content": "Qui adipisci saepe nihil est maxime labore.",
            "is_read": false,
            "created_at": "2025-01-08T10:15:52.000000Z",
            "updated_at": "2025-01-08T10:15:52.000000Z",
            "attachments": [
                {
                    "id": 6591,
                    "ticket_id": 4450,
                    "ticket_message_id": 4542,
                    "type": "application\/javascript",
                    "title": "Matilde Bins",
                    "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/008888%3Ftext%3Deveniet",
                    "created_at": "2025-01-08T10:15:52.000000Z",
                    "updated_at": "2025-01-08T10:15:52.000000Z"
                },
                {
                    "id": 6592,
                    "ticket_id": 4450,
                    "ticket_message_id": 4542,
                    "type": "application\/x-sh",
                    "title": "Xavier McGlynn",
                    "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/00dd00%3Ftext%3Dsoluta",
                    "created_at": "2025-01-08T10:15:52.000000Z",
                    "updated_at": "2025-01-08T10:15:52.000000Z"
                },
                {
                    "id": 6593,
                    "ticket_id": 4450,
                    "ticket_message_id": 4542,
                    "type": "application\/vnd.kde.kpresenter",
                    "title": "Mathias Huels IV",
                    "attachment": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/https%3A\/\/via.placeholder.com\/640x480.png\/00bb44%3Ftext%3Deos",
                    "created_at": "2025-01-08T10:15:52.000000Z",
                    "updated_at": "2025-01-08T10:15:52.000000Z"
                }
            ],
            "sender": {
                "id": 15067,
                "mrn": "UPCPEJUF",
                "name": "Dr. Maxine Will",
                "email": "1736331351mueller.alexie@example.net",
                "language": "en",
                "phone": "+1.870.441.4265",
                "phone_country": "AM",
                "phone_verified_at": null,
                "address1": "3545 Runte Station",
                "address2": "Elliotmouth, OH 08235",
                "postal_code": "97740",
                "city": "Gerhold PLC",
                "clinic_name": "Stehrport",
                "clinic_location": "186 Lowe Junction\nMagdalenaland, KS 82379-8636",
                "image": null,
                "mfa_enabled": 0,
                "mfa_method": null,
                "mfa_verified_to": null,
                "created_by": null,
                "active": 1,
                "notifications_timezone": null,
                "notifications_at": null,
                "created_at": "2025-01-08T10:15:52.000000Z",
                "updated_at": "2025-01-08T10:15:52.000000Z",
                "invitation_status": null,
                "roles": []
            }
        }
    ]
}

Request   

POST api/ticket/{id}/messages

URL Parameters

id  string  

Body Parameters

title  string optional  
Message title.

content  string optional  
Content of message.

attachments  file[] optional  
The value must be a file.

Mark all messages as read

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/ticket/10/read" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/ticket/10/read"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to read message"
}

Example response (404, Support ticket not found):

{
    "message": "Support ticket not found"
}

Example response (202):

{
    "id": 4451,
    "sender_id": 15071,
    "recipient_id": 15072,
    "device_id": 6016,
    "meeting_date": "2025-01-08T10:15:52.000000Z",
    "meeting_type": "online_meeting",
    "contact_email": "lkessler@hotmail.com",
    "status": "new",
    "created_at": "2025-01-08T10:15:52.000000Z",
    "updated_at": "2025-01-08T10:15:52.000000Z",
    "messages": [
        {
            "id": 4543,
            "ticket_id": 4451,
            "sender_id": 15073,
            "title": "Prof.",
            "content": "At tenetur corporis consectetur ducimus quo aliquid.",
            "is_read": false,
            "created_at": "2025-01-08T10:15:52.000000Z",
            "updated_at": "2025-01-08T10:15:52.000000Z"
        }
    ]
}

Request   

POST api/ticket/{id}/read

URL Parameters

id  integer  
Support Ticket ID (id from ticket list; do not confuse with messages.id).

Mark single message as read

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/ticket/10/read/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/ticket/10/read/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to read message"
}

Example response (404, Message not found):

{
    "message": "Message not found"
}

Example response (202):

{
    "id": 4452,
    "sender_id": 15077,
    "recipient_id": 15078,
    "device_id": 6018,
    "meeting_date": "2025-01-08T10:15:52.000000Z",
    "meeting_type": "online_meeting",
    "contact_email": "wkihn@littel.info",
    "status": "new",
    "created_at": "2025-01-08T10:15:52.000000Z",
    "updated_at": "2025-01-08T10:15:52.000000Z",
    "messages": [
        {
            "id": 4544,
            "ticket_id": 4452,
            "sender_id": 15079,
            "title": "Prof.",
            "content": "Dolore quis quam rerum voluptas culpa.",
            "is_read": false,
            "created_at": "2025-01-08T10:15:53.000000Z",
            "updated_at": "2025-01-08T10:15:53.000000Z"
        }
    ]
}

Request   

POST api/ticket/{id}/read/{messageId}

URL Parameters

id  integer  
Support Ticket ID (id from ticket list; do not confuse with messages.id).

messageId  integer  
Message ID

Users

API endpoints for user management

Get users list

requires authentication supports: extending models supports: pagination supports: sorting

Possible extend options:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/users?search=Tom&active=any&clinician[]=15&roles=Clinician%2CAmputee&extend=clinicians%2C+patients%2C+devices%2C+devicesAsClinician%2C+roles%2C+permissions&perpage=20&page=1&sortby=user_mrn%2C+user_name%2C+role_name%2C+date&sortdir=asc" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/users"
);

let params = {
    "search": "Tom",
    "active": "any",
    "clinician[]": "15",
    "roles": "Clinician,Amputee",
    "extend": "clinicians, patients, devices, devicesAsClinician, roles, permissions",
    "perpage": "20",
    "page": "1",
    "sortby": "user_mrn, user_name, role_name, date",
    "sortdir": "asc",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view user list"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 14917,
            "mrn": "B6C76OJ9",
            "name": "Sherman Murphy",
            "email": "1736331338rickey82@example.org",
            "language": "en",
            "phone": "947.601.2773",
            "phone_country": "HR",
            "phone_verified_at": null,
            "address1": "527 Gleason Brook",
            "address2": "Port Garret, AZ 31624",
            "postal_code": "30594",
            "city": "Trantow-Schaefer",
            "clinic_name": "Hudsonberg",
            "clinic_location": "95125 Koch Orchard Apt. 194\nNorth Coltenville, CO 21008",
            "image": null,
            "mfa_enabled": 0,
            "mfa_method": null,
            "mfa_verified_to": null,
            "created_by": null,
            "active": 1,
            "notifications_timezone": null,
            "notifications_at": null,
            "created_at": "2025-01-08T10:15:38.000000Z",
            "updated_at": "2025-01-08T10:15:38.000000Z",
            "invitation_status": null,
            "roles": [
                {
                    "id": 3,
                    "name": "Amputee"
                }
            ],
            "clinicians": [],
            "devices": [
                {
                    "id": 5879,
                    "serial": "84810468-6893-3a68-8105-8771a170813e",
                    "bluetooth_id": "c8472ed4-e5ff-3374-9923-3cd4b85a7793",
                    "model_id": null,
                    "amputee_id": 14917,
                    "firmware_version_id": null,
                    "pcb_version_id": null,
                    "active": 1,
                    "last_activity_at": "0000-00-00 00:00:00",
                    "created_at": "2025-01-08T10:15:38.000000Z",
                    "updated_at": "2025-01-08T10:15:38.000000Z"
                }
            ]
        },
        {
            "id": 14918,
            "mrn": "7OBSWL9W",
            "name": "Mr. Ryan Ullrich I",
            "email": "1736331338okertzmann@example.net",
            "language": "en",
            "phone": "(530) 358-7618",
            "phone_country": "SR",
            "phone_verified_at": null,
            "address1": "469 Little Plaza",
            "address2": "East Marcelina, DE 26085-3469",
            "postal_code": "54812-0686",
            "city": "Abernathy-Mann",
            "clinic_name": "Gaytown",
            "clinic_location": "4693 Mariane Circles Suite 774\nGarrisonhaven, LA 05415",
            "image": null,
            "mfa_enabled": 0,
            "mfa_method": null,
            "mfa_verified_to": null,
            "created_by": null,
            "active": 1,
            "notifications_timezone": null,
            "notifications_at": null,
            "created_at": "2025-01-08T10:15:38.000000Z",
            "updated_at": "2025-01-08T10:15:38.000000Z",
            "invitation_status": null,
            "roles": [
                {
                    "id": 3,
                    "name": "Amputee"
                }
            ],
            "clinicians": [],
            "devices": [
                {
                    "id": 5880,
                    "serial": "8f5ea2fc-7137-3399-8224-bef96e02265a",
                    "bluetooth_id": "c22bf1ac-b8b8-3aff-b48d-e2a62765ccb6",
                    "model_id": null,
                    "amputee_id": 14918,
                    "firmware_version_id": null,
                    "pcb_version_id": null,
                    "active": 1,
                    "last_activity_at": "0000-00-00 00:00:00",
                    "created_at": "2025-01-08T10:15:38.000000Z",
                    "updated_at": "2025-01-08T10:15:38.000000Z"
                }
            ]
        }
    ]
}

Request   

GET api/users

Query Parameters

search  string optional  
Filter users by name. For SuperAdmin role it filters by UUID.

active  string optional  
Filter users by active status (available: 0 - only inactive, 1 - only active, -1 - all users). Default: 1.

clinician  integer[] optional  
Filter users by clinician. Provide single ID (clinician=1), array of IDs (clinician[]=1&clinician[]=2) or comma-separated list of IDs (clinician=1,2).

roles  string optional  
Filter users by roles (comma-separated).

extend  string optional  
Comma-separated list of relation extensions (available: clinicians, patients, devices, devicesAsClinician, roles, permissions).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

sortby  string optional  
Sort by field (available: user_mrn, user_name, role_name, date). Default: date (desc).

sortdir  string optional  
Sort direction (available: asc, desc).

Get current user data

requires authentication supports: extending models

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/me?extend=clinicians%2C+patients%2C+devices%2C+devicesAsClinician%2C+roles%2C+permissions" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/me"
);

let params = {
    "extend": "clinicians, patients, devices, devicesAsClinician, roles, permissions",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

{
    "id": 14919,
    "mrn": "1VWTLMTY",
    "name": "Margarette Senger",
    "email": "1736331338ogorczany@example.net",
    "language": "en",
    "phone": "+1 (770) 677-9678",
    "phone_country": "LR",
    "phone_verified_at": null,
    "address1": "62649 Pascale Hollow",
    "address2": "Lucyfort, TN 42017",
    "postal_code": "18198-3133",
    "city": "Lebsack Inc",
    "clinic_name": "South Devante",
    "clinic_location": "32678 Mortimer Route Apt. 612\nIssacstad, OH 83737",
    "image": null,
    "mfa_enabled": 0,
    "mfa_method": null,
    "mfa_verified_to": null,
    "created_by": null,
    "active": 1,
    "notifications_timezone": null,
    "notifications_at": null,
    "created_at": "2025-01-08T10:15:38.000000Z",
    "updated_at": "2025-01-08T10:15:38.000000Z",
    "invitation_status": null,
    "roles": [
        {
            "id": 3,
            "name": "Amputee"
        }
    ]
}

Request   

GET api/me

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: clinicians, patients, devices, devicesAsClinician, roles, permissions).

Get other user data

requires authentication supports: extending models

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/user/3?extend=clinicians%2C+patients%2C+devices%2C+devicesAsClinician%2C+roles%2C+permissions" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/3"
);

let params = {
    "extend": "clinicians, patients, devices, devicesAsClinician, roles, permissions",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view user data"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (200):

{
    "id": 14920,
    "mrn": "2OEBEWL1",
    "name": "Stevie Walsh",
    "email": "1736331338triston.hagenes@example.org",
    "language": "en",
    "phone": "253-298-6133",
    "phone_country": "CG",
    "phone_verified_at": null,
    "address1": "9347 Price Greens Apt. 428",
    "address2": "West Jena, SD 47337-5350",
    "postal_code": "84748-7635",
    "city": "Hand, Hane and Kilback",
    "clinic_name": "West Willismouth",
    "clinic_location": "98889 Yvette Lights Apt. 858\nMitchelmouth, OR 86297-8115",
    "image": null,
    "mfa_enabled": 0,
    "mfa_method": null,
    "mfa_verified_to": null,
    "created_by": null,
    "active": 1,
    "notifications_timezone": null,
    "notifications_at": null,
    "created_at": "2025-01-08T10:15:39.000000Z",
    "updated_at": "2025-01-08T10:15:39.000000Z",
    "invitation_status": null,
    "roles": [
        {
            "id": 3,
            "name": "Amputee"
        }
    ]
}

Request   

GET api/user/{id}

URL Parameters

id  integer  
User ID.

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: clinicians, patients, devices, devicesAsClinician, roles, permissions).

Create new user account

requires authentication

Predefined permissions:

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/user" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: multipart/form-data" \
    -H "Accept: application/json" \
    -F "mrn=MRN12345678" \
    -F "name=Tom Smith" \
    -F "email=test@example.com" \
    -F "language=en" \
    -F "address1=39487 Buckridge Shore" \
    -F "address2=Melyssatown, ID 09509" \
    -F "postal_code=17538" \
    -F "city=Karolannshire" \
    -F "clinic_name=Aether" \
    -F "clinic_location=39487 Buckridge Shore" \
    -F "mfa_enabled=1" \
    -F "mfa_method=email" \
    -F "clinicians=ullam" \
    -F "notifications_timezone=Europe/Warsaw" \
    -F "notifications_at=8:00" \
    -F "role=Amputee" \
    -F "permissions=user.1.update" \
    -F "image=@/home/vhosts/api-preprod.aetherdigitaltherapy.com/storage/app/public/users/example_image.png" 
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "multipart/form-data",
    "Accept": "application/json",
};

const body = new FormData();
body.append('mrn', 'MRN12345678');
body.append('name', 'Tom Smith');
body.append('email', 'test@example.com');
body.append('language', 'en');
body.append('address1', '39487 Buckridge Shore');
body.append('address2', 'Melyssatown, ID 09509');
body.append('postal_code', '17538');
body.append('city', 'Karolannshire');
body.append('clinic_name', 'Aether');
body.append('clinic_location', '39487 Buckridge Shore');
body.append('mfa_enabled', '1');
body.append('mfa_method', 'email');
body.append('clinicians', 'ullam');
body.append('notifications_timezone', 'Europe/Warsaw');
body.append('notifications_at', '8:00');
body.append('role', 'Amputee');
body.append('permissions', 'user.1.update');
body.append('image', document.querySelector('input[name="image"]').files[0]);

fetch(url, {
    method: "POST",
    headers,
    body,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create user with given role"
}

Example response (403, E-mail in use (in another region)):

{
    "message": "E-mail address already in use (in another region)"
}

Example response (201):

{
    "id": 14921,
    "mrn": "2YI0J3C8",
    "name": "Candice Haag",
    "email": "1736331339vdietrich@example.net",
    "language": "en",
    "phone": "360-873-0308",
    "phone_country": "SA",
    "phone_verified_at": null,
    "address1": "8798 Tianna Mill Apt. 867",
    "address2": "New Torrance, DE 26793",
    "postal_code": "20355",
    "city": "McLaughlin, Jaskolski and Hand",
    "clinic_name": "Gleasonbury",
    "clinic_location": "8486 Cleo Via\nRyanland, AZ 73735-2058",
    "image": null,
    "mfa_enabled": 0,
    "mfa_method": null,
    "mfa_verified_to": null,
    "created_by": null,
    "active": 1,
    "notifications_timezone": null,
    "notifications_at": null,
    "created_at": "2025-01-08T10:15:39.000000Z",
    "updated_at": "2025-01-08T10:15:39.000000Z",
    "invitation_status": null,
    "roles": [
        {
            "id": 3,
            "name": "Amputee"
        }
    ],
    "permissions": []
}

Request   

POST api/user

Body Parameters

mrn  string optional  
Medical Record Number.

name  string optional  
User full name.

email  string  
User email. The value must be a valid email address.

language  string optional  
User language.

address1  string optional  
Address line 1.

address2  string optional  
Address line 2.

postal_code  string optional  
Postal code.

city  string optional  
City.

clinic_name  string optional  
Clinic name.

clinic_location  string optional  
Clinic location.

image  file optional  
Attached user image. The value must be an image.

mfa_enabled  boolean optional  
Super Admin only: MFA enabled.

mfa_method  string optional  
Super Admin only: MFA method. The value must be one of email or sms.

clinicians  array optional  
Array of clinician IDs.

notifications_timezone  string optional  
User notifications timezone.

notifications_at  string optional  
Time when notifications and reminders should be sent. Format: HH:MM. Set null to notify at default time. The value must be a valid date in the format H:i.

role  string  
Role name. The value must be one of Amputee, ClinicianSupport, Clinician, ClinicAdmin, or SuperAdmin.

permissions  string[] optional  
List of permissions given to this user. For now, it is used for ClinicianSupport role to give access to specific actions on specific objects/users (for example user.1.update means that user has access to update user with ID 1). You can assign both predefined permissions (already checked by some endpoints) and custom permissions (check them on your own). You can also use wildcards like user.1.* to give access to all actions for given scope.

Update user account

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/3" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: multipart/form-data" \
    -H "Accept: application/json" \
    -F "mrn=MRN12345678" \
    -F "name=Tom Smith" \
    -F "email=test@example.com" \
    -F "language=en" \
    -F "address1=8873 Evert Row Suite 985" \
    -F "address2=Stoltenbergside, RI 66564" \
    -F "postal_code=99135" \
    -F "city=Vandervortport" \
    -F "clinic_name=Aether" \
    -F "clinic_location=8873 Evert Row Suite 985" \
    -F "image_delete=1" \
    -F "mfa_enabled=1" \
    -F "mfa_method=email" \
    -F "active=1" \
    -F "clinicians=nostrum" \
    -F "notifications_timezone=Europe/Warsaw" \
    -F "notifications_at=8:00" \
    -F "role=Amputee" \
    -F "permissions=user.1.update" \
    -F "image=@/home/vhosts/api-preprod.aetherdigitaltherapy.com/storage/app/public/users/example_image.png" 
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/3"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "multipart/form-data",
    "Accept": "application/json",
};

const body = new FormData();
body.append('mrn', 'MRN12345678');
body.append('name', 'Tom Smith');
body.append('email', 'test@example.com');
body.append('language', 'en');
body.append('address1', '8873 Evert Row Suite 985');
body.append('address2', 'Stoltenbergside, RI 66564');
body.append('postal_code', '99135');
body.append('city', 'Vandervortport');
body.append('clinic_name', 'Aether');
body.append('clinic_location', '8873 Evert Row Suite 985');
body.append('image_delete', '1');
body.append('mfa_enabled', '1');
body.append('mfa_method', 'email');
body.append('active', '1');
body.append('clinicians', 'nostrum');
body.append('notifications_timezone', 'Europe/Warsaw');
body.append('notifications_at', '8:00');
body.append('role', 'Amputee');
body.append('permissions', 'user.1.update');
body.append('image', document.querySelector('input[name="image"]').files[0]);

fetch(url, {
    method: "PUT",
    headers,
    body,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update user data"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (403, Insufficient permission to assign role):

{
    "message": "Insufficient permission to assign this role as ClinicAdmin"
}

Example response (202):

{
    "id": 14922,
    "mrn": "94TKFPDT",
    "name": "Olin Rippin",
    "email": "1736331339laron80@example.net",
    "language": "en",
    "phone": "213-699-3553",
    "phone_country": "TF",
    "phone_verified_at": null,
    "address1": "9665 Avery Islands Apt. 991",
    "address2": "Winifredbury, WV 45311-1610",
    "postal_code": "00039",
    "city": "Kohler-Lockman",
    "clinic_name": "South Evan",
    "clinic_location": "35965 Zaria Mission Suite 261\nNew Genoveva, AR 62241-4049",
    "image": null,
    "mfa_enabled": 0,
    "mfa_method": null,
    "mfa_verified_to": null,
    "created_by": null,
    "active": 1,
    "notifications_timezone": null,
    "notifications_at": null,
    "created_at": "2025-01-08T10:15:39.000000Z",
    "updated_at": "2025-01-08T10:15:39.000000Z",
    "invitation_status": null,
    "roles": [
        {
            "id": 3,
            "name": "Amputee"
        }
    ]
}

Request   

PUT api/user/{id}

URL Parameters

id  integer  
User ID.

Body Parameters

mrn  string optional  
Medical Record Number.

name  string optional  
User full name.

email  string optional  
User email. The value must be a valid email address.

language  string optional  
User language.

address1  string optional  
Address line 1.

address2  string optional  
Address line 2.

postal_code  string optional  
Postal code.

city  string optional  
City.

clinic_name  string optional  
Clinic name.

clinic_location  string optional  
Clinic location.

image  file optional  
Attached user image. The value must be an image.

image_delete  boolean optional  
Send this parameter instead of image to remove previously added image.

mfa_enabled  boolean optional  
Super Admin only: MFA enabled.

mfa_method  string optional  
Super Admin only: MFA method. The value must be one of email or sms.

active  boolean optional  
User active status (0 - inactive, 1 - active).

clinicians  array optional  
Array of clinician IDs.

notifications_timezone  string optional  
User notifications timezone.

notifications_at  string optional  
Time when notifications and reminders should be sent. Format: HH:MM. Set null to notify at default time. The value must be a valid date in the format H:i.

role  string optional  
Role name. The value must be one of Amputee, ClinicianSupport, Clinician, ClinicAdmin, or SuperAdmin.

permissions  string[] optional  
List of permissions given to this user. For now, it is used for ClinicianSupport role to give access to specific actions on specific objects/users (for example user.1.update means that user has access to update user with ID 1). You can assign both predefined permissions (already checked by some endpoints) and custom permissions (check them on your own). You can also use wildcards like user.1.* to give access to all actions for given scope.

Update user phone number

requires authentication

Phone number has to be verified after update. Call /api/mfa/phone/verify with user-filled code after performing this operation. If value is "0" phone number will be removed without any verification.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/3/phone" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"phone":"+1 (208) 892-0242","phone_country":"US"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/3/phone"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "phone": "+1 (208) 892-0242",
    "phone_country": "US"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (500, Code send failed):

{
    "message": "Verification code sending failed"
}

Example response (200, Phone number removed):

{
    "message": "Phone number removed"
}

Example response (200):

{
    "message": "Verification code sent. Call \/api\/mfa\/phone\/verify to verify phone number."
}

Request   

POST api/user/{id}/phone

URL Parameters

id  integer  
User ID.

Body Parameters

phone  string optional  
User phone number. Pass "0" to remove current one.

phone_country  string optional  
Phone number's country (2 characters).

Delete user account

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/3" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/3"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to delete user"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (403, User has existing devices):

{
    "message": "Cannot delete: user has existing devices (as patient: 1, as clinician: 0)"
}

Example response (403, User has open P2P sessions):

{
    "message": "Cannot delete: user has open P2P sessions (as patient: 0, as clinician: 1)"
}

Example response (500, Server error):

{
    "message": "Server error: user not deleted",
    "code": "USER:DELETE:SERVER_ERROR"
}

Example response (202):

{
    "message": "User deleted"
}

Request   

DELETE api/user/{id}

URL Parameters

id  integer  
User ID.

Change other user password

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/3/password" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"password":"minima"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/3/password"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "password": "minima"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to change user password"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (202):

{
    "message": "User password changed"
}

Request   

POST api/user/{id}/password

URL Parameters

id  integer  
User ID.

Body Parameters

password  string  

Get user devices list

requires authentication supports: extending models supports: pagination

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/user/12/devices?extend=model%2C+firmwareVersion%2C+pcbVersion&perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/12/devices"
);

let params = {
    "extend": "model, firmwareVersion, pcbVersion",
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to view user devices"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 5885,
            "serial": "0fe830e7-d9a0-333e-a194-d8294e98f1ce",
            "bluetooth_id": "d9af0062-e823-34ca-a6bc-4c69d47fa09a",
            "model_id": 188,
            "amputee_id": null,
            "firmware_version_id": null,
            "pcb_version_id": null,
            "active": 1,
            "last_activity_at": "0000-00-00 00:00:00",
            "created_at": "2025-01-08T10:15:39.000000Z",
            "updated_at": "2025-01-08T10:15:39.000000Z",
            "model": {
                "id": 188,
                "name": "Zeus hand v1",
                "type": "leg",
                "orientation": "left",
                "active": 1,
                "created_at": "2025-01-08T10:15:39.000000Z",
                "updated_at": "2025-01-08T10:15:39.000000Z"
            }
        },
        {
            "id": 5886,
            "serial": "55e9d517-fc96-3836-a05c-375bddfa4d20",
            "bluetooth_id": "79208f80-955a-3af1-868d-21e169b78951",
            "model_id": 189,
            "amputee_id": null,
            "firmware_version_id": null,
            "pcb_version_id": null,
            "active": 1,
            "last_activity_at": "0000-00-00 00:00:00",
            "created_at": "2025-01-08T10:15:39.000000Z",
            "updated_at": "2025-01-08T10:15:39.000000Z",
            "model": {
                "id": 189,
                "name": "Zeus hand v1",
                "type": "arm",
                "orientation": "left",
                "active": 1,
                "created_at": "2025-01-08T10:15:39.000000Z",
                "updated_at": "2025-01-08T10:15:39.000000Z"
            }
        }
    ]
}

Request   

GET api/user/{id}/devices

URL Parameters

id  integer  
User ID

Query Parameters

extend  string optional  
Comma-separated list of relation extensions (available: model, firmwareVersion, pcbVersion).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Attach patient to clinician

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/attach" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"email":"name@domain.com"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/attach"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "name@domain.com"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to attach patients"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (202):

{
    "message": "Patient attached"
}

Request   

POST api/user/attach

Body Parameters

email  string  
User e-mail address. The value must be a valid email address.

Detach patient from clinician

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/user/3/detach" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/user/3/detach"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to detach patient"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (403, Cannot detach last clinician):

{
    "message": "Cannot detach patient's last clinician"
}

Example response (202):

{
    "message": "Patient detached"
}

Request   

POST api/user/{id}/detach

URL Parameters

id  integer  
User ID.

Get user mobile consents

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/consents" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/consents"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to use mobile consents"
}

Example response (200):

[
    {
        "id": 22,
        "user_id": 1,
        "name": "blanditiis",
        "value": "quidem",
        "created_at": "1976-05-19T02:29:37.000000Z",
        "updated_at": "1987-08-09T18:36:08.000000Z"
    },
    {
        "id": 23,
        "user_id": 1,
        "name": "deserunt",
        "value": "omnis",
        "created_at": "1991-08-29T21:47:06.000000Z",
        "updated_at": "1979-02-19T19:52:07.000000Z"
    }
]

Request   

GET api/consents

Set user mobile consent

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/consents" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"Push notifications","value":1}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/consents"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Push notifications",
    "value": 1
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to use mobile consents"
}

Example response (200):

[
    {
        "id": 24,
        "user_id": 1,
        "name": "sit",
        "value": "quibusdam",
        "created_at": "1971-01-31T17:20:32.000000Z",
        "updated_at": "2020-05-08T20:44:51.000000Z"
    },
    {
        "id": 25,
        "user_id": 1,
        "name": "est",
        "value": "quidem",
        "created_at": "1994-09-04T05:11:44.000000Z",
        "updated_at": "2000-10-29T10:33:26.000000Z"
    }
]

Request   

POST api/consents

Body Parameters

name  string  
Consent name.

value  string  
Consent value.

Clear user notifications

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/notifications/3" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/notifications/3"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update user data"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (202):

{
    "messages": "1 notifications deleted"
}

Request   

DELETE api/notifications/{id}

URL Parameters

id  integer  
User ID.

Versions

Get software versions

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/versions/software" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/software"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

[
    {
        "id": 192,
        "name": "3.37.61",
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    },
    {
        "id": 193,
        "name": "7.20.68",
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    }
]

Request   

GET api/versions/software

Create software version

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/software" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"1.0"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/software"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "1.0"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create versions"
}

Example response (201):

{
    "id": 194,
    "name": "3.12.30",
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

POST api/versions/software

Body Parameters

name  string  
Name of version.

Delete software version

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/software/2" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/software/2"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create versions"
}

Example response (404, Version not found):

{
    "message": "Version not found"
}

Example response (403, Version in use):

{
    "message": "Cannot delete: version is used in compatibility entries (1)"
}

Example response (202):

{
    "message": "Version deleted"
}

Request   

DELETE api/versions/software/{id}

URL Parameters

id  integer  
Software Version ID

Get firmware versions

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

[
    {
        "id": 236,
        "name": "9.33.92",
        "file_firmware": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerJmv3jE",
        "file_firmware_new_pcb": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakervN2ilT",
        "file_firmware_v2": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakeruYmYvz",
        "file_firmware_v3": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerSmfgsA",
        "file_firmware_v4": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/faker7F0Dwr",
        "file_bootloader": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerlVuCLK",
        "file_bootloader_v2": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakero16ruu",
        "file_bootloader_v3": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerAvYpP3",
        "file_bootloader_v4": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerYhFZPp",
        "changelog": "Quia repellat rerum dolores sint perferendis laborum laborum. Natus omnis quae aspernatur explicabo ut similique commodi. Cumque fuga repellendus sit error consequuntur.",
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    },
    {
        "id": 237,
        "name": "4.53.85",
        "file_firmware": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerFN1DpK",
        "file_firmware_new_pcb": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/faker4tf1Dt",
        "file_firmware_v2": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerbws0XT",
        "file_firmware_v3": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakersRJh69",
        "file_firmware_v4": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerS79YQA",
        "file_bootloader": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerEIxZmt",
        "file_bootloader_v2": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerHMx5m9",
        "file_bootloader_v3": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakeranQQ46",
        "file_bootloader_v4": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerDwEDvt",
        "changelog": "Et et maiores et similique molestias omnis ratione. Nisi et ad ea repudiandae ut repudiandae. Quibusdam porro omnis deleniti praesentium cumque. Quis minus possimus quibusdam.",
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    }
]

Request   

GET api/versions/firmware

Create firmware version

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: multipart/form-data" \
    -H "Accept: application/json" \
    -F "name=1.0" \
    -F "changelog=Fixed bug with the connection" \
    -F "file_firmware=@/tmp/phpF0YtaI"     -F "file_firmware_v2=@/tmp/phpH6kTy0"     -F "file_firmware_v3=@/tmp/php6284y5"     -F "file_firmware_v4=@/tmp/phpx3i54l"     -F "file_firmware_new_pcb=@/tmp/phpTLRf4W"     -F "file_bootloader=@/tmp/php6E9r83"     -F "file_bootloader_v2=@/tmp/phpDjVlVG"     -F "file_bootloader_v3=@/tmp/php5xfE0M"     -F "file_bootloader_v4=@/tmp/phpKl2cBv" 
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "multipart/form-data",
    "Accept": "application/json",
};

const body = new FormData();
body.append('name', '1.0');
body.append('changelog', 'Fixed bug with the connection');
body.append('file_firmware', document.querySelector('input[name="file_firmware"]').files[0]);
body.append('file_firmware_v2', document.querySelector('input[name="file_firmware_v2"]').files[0]);
body.append('file_firmware_v3', document.querySelector('input[name="file_firmware_v3"]').files[0]);
body.append('file_firmware_v4', document.querySelector('input[name="file_firmware_v4"]').files[0]);
body.append('file_firmware_new_pcb', document.querySelector('input[name="file_firmware_new_pcb"]').files[0]);
body.append('file_bootloader', document.querySelector('input[name="file_bootloader"]').files[0]);
body.append('file_bootloader_v2', document.querySelector('input[name="file_bootloader_v2"]').files[0]);
body.append('file_bootloader_v3', document.querySelector('input[name="file_bootloader_v3"]').files[0]);
body.append('file_bootloader_v4', document.querySelector('input[name="file_bootloader_v4"]').files[0]);

fetch(url, {
    method: "POST",
    headers,
    body,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create versions"
}

Example response (201):

{
    "id": 238,
    "name": "8.33.93",
    "file_firmware": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerifD5WJ",
    "file_firmware_new_pcb": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerSoSKEw",
    "file_firmware_v2": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/faker5iyrlS",
    "file_firmware_v3": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakertPn4TX",
    "file_firmware_v4": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerf37ey8",
    "file_bootloader": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerwSaHVc",
    "file_bootloader_v2": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakernaPT9G",
    "file_bootloader_v3": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerqS6O2k",
    "file_bootloader_v4": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakervIrW5w",
    "changelog": "Similique aliquid hic a sint ad. Sequi qui eligendi nobis et quae repudiandae sequi. At tenetur aperiam necessitatibus quaerat id repudiandae.",
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

POST api/versions/firmware

Body Parameters

name  string  
Name of version.

file_firmware  file optional  
Attached firmware file. The value must be a file.

file_firmware_v2  file optional  
Attached firmware file. The value must be a file.

file_firmware_v3  file optional  
Attached firmware file. The value must be a file.

file_firmware_v4  file optional  
Attached firmware file. The value must be a file.

file_firmware_new_pcb  file optional  
Attached firmware for new PCB file. The value must be a file.

file_bootloader  file optional  
Attached bootloader file. The value must be a file.

file_bootloader_v2  file optional  
Attached bootloader file. The value must be a file.

file_bootloader_v3  file optional  
Attached bootloader file. The value must be a file.

file_bootloader_v4  file optional  
Attached bootloader file. The value must be a file.

changelog  string optional  
Changelog for the version.

Update firmware version

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware/qui" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: multipart/form-data" \
    -H "Accept: application/json" \
    -F "name=1.0" \
    -F "changelog=Fixed bug with the connection" \
    -F "file_firmware_delete=1" \
    -F "file_firmware_v2_delete=1" \
    -F "file_firmware_v3_delete=1" \
    -F "file_firmware_v4_delete=1" \
    -F "file_firmware_new_pcb_delete=1" \
    -F "file_bootloader_delete=1" \
    -F "file_bootloader_v2_delete=1" \
    -F "file_bootloader_v3_delete=1" \
    -F "file_bootloader_v4_delete=1" \
    -F "file_firmware=@/tmp/phpp8eHrA"     -F "file_firmware_v2=@/tmp/phpDYhykv"     -F "file_firmware_v3=@/tmp/phpxN2eQr"     -F "file_firmware_v4=@/tmp/phpaATPc2"     -F "file_firmware_new_pcb=@/tmp/phpVnrIcU"     -F "file_bootloader=@/tmp/phpdHXV5q"     -F "file_bootloader_v2=@/tmp/phpynbmxa"     -F "file_bootloader_v3=@/tmp/phpi6vRAH"     -F "file_bootloader_v4=@/tmp/php7Dlgqx" 
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware/qui"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "multipart/form-data",
    "Accept": "application/json",
};

const body = new FormData();
body.append('name', '1.0');
body.append('changelog', 'Fixed bug with the connection');
body.append('file_firmware_delete', '1');
body.append('file_firmware_v2_delete', '1');
body.append('file_firmware_v3_delete', '1');
body.append('file_firmware_v4_delete', '1');
body.append('file_firmware_new_pcb_delete', '1');
body.append('file_bootloader_delete', '1');
body.append('file_bootloader_v2_delete', '1');
body.append('file_bootloader_v3_delete', '1');
body.append('file_bootloader_v4_delete', '1');
body.append('file_firmware', document.querySelector('input[name="file_firmware"]').files[0]);
body.append('file_firmware_v2', document.querySelector('input[name="file_firmware_v2"]').files[0]);
body.append('file_firmware_v3', document.querySelector('input[name="file_firmware_v3"]').files[0]);
body.append('file_firmware_v4', document.querySelector('input[name="file_firmware_v4"]').files[0]);
body.append('file_firmware_new_pcb', document.querySelector('input[name="file_firmware_new_pcb"]').files[0]);
body.append('file_bootloader', document.querySelector('input[name="file_bootloader"]').files[0]);
body.append('file_bootloader_v2', document.querySelector('input[name="file_bootloader_v2"]').files[0]);
body.append('file_bootloader_v3', document.querySelector('input[name="file_bootloader_v3"]').files[0]);
body.append('file_bootloader_v4', document.querySelector('input[name="file_bootloader_v4"]').files[0]);

fetch(url, {
    method: "PUT",
    headers,
    body,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update versions"
}

Example response (403, Version not found):

{
    "message": "Version not found"
}

Example response (202):

{
    "id": 239,
    "name": "9.16.54",
    "file_firmware": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakervDsPLi",
    "file_firmware_new_pcb": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerYkmwlJ",
    "file_firmware_v2": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/faker4Sq7vW",
    "file_firmware_v3": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerJGlNiG",
    "file_firmware_v4": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerBSNiCb",
    "file_bootloader": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerap1DCC",
    "file_bootloader_v2": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerBuo7Xb",
    "file_bootloader_v3": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerdnurw9",
    "file_bootloader_v4": "https:\/\/aether-preprod-bucket.s3.amazonaws.com\/\/tmp\/fakerFB4zws",
    "changelog": "Dolores doloribus rerum maiores ut. Aliquam id consequatur quis delectus rerum. Impedit velit tempore nemo.",
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

PUT api/versions/firmware/{id}

URL Parameters

id  string  

Body Parameters

name  string optional  
Name of version.

file_firmware  file optional  
Attached firmware file. The value must be a file.

file_firmware_v2  file optional  
Attached firmware file. The value must be a file.

file_firmware_v3  file optional  
Attached firmware file. The value must be a file.

file_firmware_v4  file optional  
Attached firmware file. The value must be a file.

file_firmware_new_pcb  file optional  
Attached firmware for new PCB file. The value must be a file.

file_bootloader  file optional  
Attached bootloader file. The value must be a file.

file_bootloader_v2  file optional  
Attached bootloader file. The value must be a file.

file_bootloader_v3  file optional  
Attached bootloader file. The value must be a file.

file_bootloader_v4  file optional  
Attached bootloader file. The value must be a file.

changelog  string optional  
Changelog for the version.

file_firmware_delete  string optional  
Send this parameter with value 1 to remove existing file for file_firmware.

file_firmware_v2_delete  string optional  
Send this parameter with value 1 to remove existing file for file_firmware_v2.

file_firmware_v3_delete  string optional  
Send this parameter with value 1 to remove existing file for file_firmware_v3.

file_firmware_v4_delete  string optional  
Send this parameter with value 1 to remove existing file for file_firmware_v4.

file_firmware_new_pcb_delete  string optional  
Send this parameter with value 1 to remove existing file for file_firmware_new_pcb.

file_bootloader_delete  string optional  
Send this parameter with value 1 to remove existing file for file_bootloader.

file_bootloader_v2_delete  string optional  
Send this parameter with value 1 to remove existing file for file_bootloader_v2.

file_bootloader_v3_delete  string optional  
Send this parameter with value 1 to remove existing file for file_bootloader_v3.

file_bootloader_v4_delete  string optional  
Send this parameter with value 1 to remove existing file for file_bootloader_v4.

Delete firmware version

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware/9" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/firmware/9"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create versions"
}

Example response (404, Version not found):

{
    "message": "Version not found"
}

Example response (403, Version in use (compatibility)):

{
    "message": "Cannot delete: version is used in compatibility entries (1)"
}

Example response (403, Version in use (device)):

{
    "message": "Cannot delete: version is assigned to devices (1)"
}

Example response (202):

{
    "message": "Version deleted"
}

Request   

DELETE api/versions/firmware/{id}

URL Parameters

id  integer  
Firmware Version ID

Get PCB versions

requires authentication

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/versions/pcb" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/pcb"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

[
    {
        "id": 139,
        "name": "9.19.97",
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    },
    {
        "id": 140,
        "name": "5.84.55",
        "created_at": "2025-01-08T10:15:53.000000Z",
        "updated_at": "2025-01-08T10:15:53.000000Z"
    }
]

Request   

GET api/versions/pcb

Create PCB version

requires authentication

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/pcb" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"name":"1.0"}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/pcb"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "1.0"
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):

{
    "message": "Insufficient permission to create versions"
}

Example response (200):

{
    "id": 141,
    "name": "7.34.39",
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

POST api/versions/pcb

Body Parameters

name  string  
Name of version.

Delete PCB version

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/pcb/2" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/pcb/2"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to create versions"
}

Example response (404, Version not found):

{
    "message": "Version not found"
}

Example response (403, Version in use (compatibility)):

{
    "message": "Cannot delete: version is used in compatibility entries (1)"
}

Example response (403, Version in use (device)):

{
    "message": "Cannot delete: version is assigned to devices (1)"
}

Example response (202):

{
    "message": "Version deleted"
}

Request   

DELETE api/versions/pcb/{id}

URL Parameters

id  integer  
PCB Version ID

List compatibilities

requires authentication supports: extending models supports: pagination

Most typical scenarios to use compatibility matrix:

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/versions/compatibility?model=1&software=1.2&firmware=1.5&pcb=1.0&summary=1&extend=features%2C+features.feature%2C+deviceModel%2C+softwareVersion%2C+firmwareVersion%2C+pcbVersion&perpage=20&page=1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/compatibility"
);

let params = {
    "model": "1",
    "software": "1.2",
    "firmware": "1.5",
    "pcb": "1.0",
    "summary": "1",
    "extend": "features, features.feature, deviceModel, softwareVersion, firmwareVersion, pcbVersion",
    "perpage": "20",
    "page": "1",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to list versions compatibilities"
}

Example response (404, Device model not found):

{
    "message": "Device model not found"
}

Example response (404, Software version not found):

{
    "message": "Software version not found"
}

Example response (404, Firmware version not found):

{
    "message": "Firmware version not found"
}

Example response (404, PCB version not found):

{
    "message": "PCB version not found"
}

Example response (200):

{
    "paginator": {
        "total": 2,
        "count": 2,
        "perpage": 20,
        "current_page": 1,
        "last_page": 1
    },
    "items": [
        {
            "id": 628,
            "device_model_id": 197,
            "software_version_id": 195,
            "firmware_version_id": 248,
            "pcb_version_id": 142,
            "is_fully_compatible": 0,
            "created_at": "2025-01-08T10:15:53.000000Z",
            "updated_at": "2025-01-08T10:15:53.000000Z",
            "features": [
                {
                    "id": 2980,
                    "compatibility_id": 628,
                    "feature_id": 80,
                    "is_compatible": 0,
                    "reason": "Magnam soluta qui molestiae est. Corporis qui et iste veritatis ipsum. Blanditiis dolorem assumenda dolor fugiat qui delectus. Et sint et sint exercitationem possimus numquam.",
                    "created_at": "2025-01-08T10:15:53.000000Z",
                    "updated_at": "2025-01-08T10:15:53.000000Z",
                    "feature": {
                        "id": 80,
                        "name": "white",
                        "slug": "molestiae-earum-pariatur-voluptas-asperiores-illum",
                        "created_at": "2025-01-08T10:15:53.000000Z",
                        "updated_at": "2025-01-08T10:15:53.000000Z"
                    }
                }
            ]
        },
        {
            "id": 630,
            "device_model_id": 199,
            "software_version_id": 197,
            "firmware_version_id": 250,
            "pcb_version_id": 144,
            "is_fully_compatible": 1,
            "created_at": "2025-01-08T10:15:53.000000Z",
            "updated_at": "2025-01-08T10:15:53.000000Z",
            "features": [
                {
                    "id": 2981,
                    "compatibility_id": 630,
                    "feature_id": 82,
                    "is_compatible": 1,
                    "reason": "Eum quis inventore at voluptatem voluptatem. Aspernatur sed fugit porro quaerat. Tempore dolorem non eveniet id sit ut nulla facilis.",
                    "created_at": "2025-01-08T10:15:53.000000Z",
                    "updated_at": "2025-01-08T10:15:53.000000Z",
                    "feature": {
                        "id": 82,
                        "name": "navy",
                        "slug": "rem-quo-et-voluptatem-et-consequatur-odit-eum",
                        "created_at": "2025-01-08T10:15:53.000000Z",
                        "updated_at": "2025-01-08T10:15:53.000000Z"
                    }
                }
            ]
        }
    ]
}

Request   

GET api/versions/compatibility

Query Parameters

model  integer optional  
Filter compatibility matrix by device model ID.

software  string optional  
Filter compatibility matrix by software version name (not ID!).

firmware  string optional  
Filter compatibility matrix by firmware version name (not ID!).

pcb  string optional  
Filter compatibility matrix by PCB version name (not ID!).

summary  boolean optional  
Add to response the device model, software, firmware and PCB entries used to filter the list.

extend  string optional  
Comma-separated list of relation extensions (available: features, features.feature, deviceModel, softwareVersion, firmwareVersion, pcbVersion).

perpage  integer optional  
Elements per page (Default: 20).

page  integer optional  
Page number (Default: 1).

Add compatibility

requires authentication

Adds or updates compatibility matrix with assigned features. You can specify many versions for each list.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/compatibility" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"device_models":[1,15],"software_versions":[1,12],"firmware_versions":[1,7],"pcb_versions":[1,10],"is_fully_compatible":1,"features":[{"feature_id":1,"compatible":1,"reason":"Firmware does not support..."}]}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/compatibility"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "device_models": [
        1,
        15
    ],
    "software_versions": [
        1,
        12
    ],
    "firmware_versions": [
        1,
        7
    ],
    "pcb_versions": [
        1,
        10
    ],
    "is_fully_compatible": 1,
    "features": [
        {
            "feature_id": 1,
            "compatible": 1,
            "reason": "Firmware does not support..."
        }
    ]
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to add versions compatibility"
}

Example response (202):

{
    "added": 1,
    "updated": 0,
    "not_changed": 0
}

Request   

POST api/versions/compatibility

Body Parameters

device_models  integer[] optional  
Array of Device Model IDs.

software_versions  integer[] optional  
Array of Software Version IDs.

firmware_versions  integer[] optional  
Array of Firmware Version IDs.

pcb_versions  integer[] optional  
Array of PCB Version IDs.

is_fully_compatible  integer optional  
Is this set of versions fully compatible? The value must be one of 0 or 1.

features  object[] optional  

features[].feature_id  string optional  
Product feature ID.

features[].compatible  integer optional  
Is this feature compatible? The value must be one of 0 or 1.

features[].reason  string optional  
Reason of incompatibility.

Update compatibility

requires authentication

Example request:

curl -X PUT \
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/compatibility/17" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"device_model_id":1,"software_version_id":5,"firmware_version_id":14,"pcb_version_id":1,"is_fully_compatible":1,"features":[{"id":1,"feature_id":1,"compatible":1,"reason":"Firmware does not support...","delete":1}]}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/compatibility/17"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "device_model_id": 1,
    "software_version_id": 5,
    "firmware_version_id": 14,
    "pcb_version_id": 1,
    "is_fully_compatible": 1,
    "features": [
        {
            "id": 1,
            "feature_id": 1,
            "compatible": 1,
            "reason": "Firmware does not support...",
            "delete": 1
        }
    ]
}

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to update versions compatibility"
}

Example response (200):

{
    "id": 632,
    "device_model_id": 201,
    "software_version_id": 199,
    "firmware_version_id": 252,
    "pcb_version_id": 146,
    "is_fully_compatible": 1,
    "created_at": "2025-01-08T10:15:53.000000Z",
    "updated_at": "2025-01-08T10:15:53.000000Z"
}

Request   

PUT api/versions/compatibility/{id}

URL Parameters

id  integer  
Versions Compatibility ID

Body Parameters

device_model_id  integer optional  
Device Model ID.

software_version_id  integer optional  
Software Version ID.

firmware_version_id  integer optional  
Firmware Version ID.

pcb_version_id  integer optional  
PCB Version ID.

is_fully_compatible  integer optional  
Is this set of versions fully compatible? The value must be one of 0 or 1.

features  object[] optional  

features[].id  string optional  
Versions compatibility feature ID. Use with delete parameter to delete specific entry. Do not confuse with feature_id, this field refers to ID of relation between versions compatibility and product feature.

features[].feature_id  string optional  
Product feature ID.

features[].compatible  integer optional  
Is this feature compatible? The value must be one of 0 or 1.

features[].reason  string optional  
Reason of incompatibility.

features[].delete  integer optional  
Pass 1 to detach feature from this set of versions, skip otherwise. The value must be one of 1.

Delete compatibility

requires authentication

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/compatibility/14" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/versions/compatibility/14"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to delete versions compatibility"
}

Example response (404, Versions compatibility not found):

{
    "message": "Versions compatibility not found"
}

Example response (202):

{
    "message": "Versions compatibility deleted"
}

Request   

DELETE api/versions/compatibility/{id}

URL Parameters

id  integer  
Versions Compatibility ID

Video sessions

API endpoints for managing video sessions

List video sessions

requires authentication

Returns list of open video sessions. For most cases there should be exactly one entry (open/active session) or exactly zero entries (empty array, no open sessions).

Example request:

curl -X GET \
    -G "https://api-preprod.aetherdigitaltherapy.com/api/sessions/video/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/sessions/video/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to access video session"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (200):

[
    {
        "id": 758,
        "moderator_id": 15001,
        "guest_id": 15002,
        "jwt_moderator": "5be1bec126f45d500efb357429e093d4bed0375e2c1177a2df12de4fee811023",
        "jwt_guest": "1bbad7b249edcb08912a0bfe0777a4b02073ccaaba1ccb331f10b1f4e4789c9a",
        "room_name": "room_1714cc7ff178fbbd1d5672a7cee1f1d8",
        "expires": 1736332246,
        "status": "open",
        "created_at": "2025-01-08T10:15:46.000000Z",
        "updated_at": "2025-01-08T10:15:46.000000Z"
    },
    {
        "id": 759,
        "moderator_id": 15005,
        "guest_id": 15006,
        "jwt_moderator": "28ce024bf7c9ea106faf8a999e18133e5831c662f22029e089b99ce389cf0739",
        "jwt_guest": "5f53b0a2be22e28dc4b056f663910c046a33f9b2d779eaf997ea771fe1881a13",
        "room_name": "room_1714cc7ff178fbbd1d5672a7cee1f1d8",
        "expires": 1736332246,
        "status": "open",
        "created_at": "2025-01-08T10:15:46.000000Z",
        "updated_at": "2025-01-08T10:15:46.000000Z"
    }
]

Request   

GET api/sessions/video/{guestId}

URL Parameters

guestId  integer  
User ID (guest of the meeting).

Initialize video session

requires authentication

Creates JWT (JSON Web Token) and room name for Jitsi session. Logged-in user is a moderator of the session. JWT lifetime is 15 minutes.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/sessions/video/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/sessions/video/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to initialize video session"
}

Example response (404, User not found):

{
    "message": "User not found"
}

Example response (500, Key file not found):

{
    "message": "Key file not found."
}

Example response (200):

{
    "id": 760,
    "moderator_id": 15009,
    "guest_id": 15010,
    "jwt_moderator": "a2842c2b6a471f2ef963ecb6d01620231bc8a54f56e0b62e8ebab82a2a941b9b",
    "jwt_guest": "18b0a5cf1a7565679ecd1f845ca85ac1870c5b4e927fbd717784b71243dc287d",
    "room_name": "room_5b9964043b051c19153b500ac0d61313",
    "expires": 1736332247,
    "status": "open",
    "created_at": "2025-01-08T10:15:47.000000Z",
    "updated_at": "2025-01-08T10:15:47.000000Z"
}

Request   

POST api/sessions/video/{guestId}

URL Parameters

guestId  integer  
User ID (guest of the meeting).

Refresh video session

requires authentication

Refreshes video session JWT tokens to extend session lifetime.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/sessions/video/1/refresh" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/sessions/video/1/refresh"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to refresh video session"
}

Example response (404, Session not found):

{
    "message": "Video session not found"
}

Example response (202):

{
    "id": 761,
    "moderator_id": 15013,
    "guest_id": 15014,
    "jwt_moderator": "3f6843b96048c796a3865c99f0ed90b0cdda5d970d2b0bf609714dba3c9975c1",
    "jwt_guest": "0d4f3e0e8faf0dc6d28655c8d8b6fdc2e5e30f256e96ca1f2f6669270fd1c618",
    "room_name": "room_5b9964043b051c19153b500ac0d61313",
    "expires": 1736332247,
    "status": "open",
    "created_at": "2025-01-08T10:15:47.000000Z",
    "updated_at": "2025-01-08T10:15:47.000000Z"
}

Request   

POST api/sessions/video/{sessionId}/refresh

URL Parameters

sessionId  string optional  
Video Session ID.

Close video session

requires authentication

Marks video session (database entry) as closed. Does not close session on Jitsi side.

Example request:

curl -X DELETE \
    "https://api-preprod.aetherdigitaltherapy.com/api/sessions/video/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json"
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/sessions/video/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to close video session"
}

Example response (404, Session not found):

{
    "message": "Video session not found"
}

Example response (202):

{
    "message": "Video session closed"
}

Request   

DELETE api/sessions/video/{sessionId}

URL Parameters

sessionId  string optional  
Video Session ID.

Invite technical support

requires authentication

Sends notification to Slack channel. Link to meeting is valid for 10 minutes.

Example request:

curl -X POST \
    "https://api-preprod.aetherdigitaltherapy.com/api/sessions/video/invite-support/1" \
    -H "Authorization: Bearer {ACCESS_TOKEN}" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{"room":"room_1081c785cf1464e4d6ebc3976561d490","description":"Grip switching is not working, please join."}'
const url = new URL(
    "https://api-preprod.aetherdigitaltherapy.com/api/sessions/video/invite-support/1"
);

let headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "room": "room_1081c785cf1464e4d6ebc3976561d490",
    "description": "Grip switching is not working, please join."
}

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (403, Insufficient permission):

{
    "message": "Insufficient permission to invite tech support"
}

Example response (404, Device not found):

{
    "message": "Device not found"
}

Example response (500, Request failed):

{
    "response": "invalid_payload"
}

Example response (200):

{
    "response": "success"
}

Request   

POST api/sessions/video/invite-support/{deviceId}

URL Parameters

deviceId  integer  
Device ID (current device of the session).

Body Parameters

room  string  
Name of Jitsi room to connect.

description  string optional  
Description of problem provided by clinician.