# Corona Tracker
## Overview
1. JSON Rest with Bearer token authorization
2. Validation errors returned with `422` status code (Dont run any retry logic for this status 4xx status codes)
3. API base `https://togetherwecan-api-00.arimac.digital/api`
4. The app uses 2 types for tokens. A short lived token issued when user authenticating, a long lived token with scope set to `encounters:submit` to submit encounters.
**Sample error response**
**Response**
{
"errors": [
"error 1",
"error 2"
]
}
## Common endpoints
### Login
The JWT token include a custom claim called `scope` which includes user's token scope list in an _array_.
Below scopes are currently utylized by the system
- **profile** for users assigned when authenticated using sms otp method
- **analyze** for admin users
#### POST /auth/login
**Request**
{
"email": "sahan@demo.com",
"password": "sahan123",
"scopes": ["analyze"],
"captcha_response": "sdsdsd"
}
**Response**
{
"token": "<token>"
}
## User endpoints
### Request a OTP
Before a user is registered an OTP should be obtained
#### POST /auth/otp
**Request**
{
"phone": "772754541"
}
**Response**
{
"success": true
}
### Register a user
Provide a phone number and OTP code to register. If user is already registered system will update the existing record.
#### POST /auth/register
**Request**
{
"phone": "772754541",
"code" : "1234"
}
**Response**
{
token_type": "Bearer",
"expires_in": 1296000,
"access_token": "...",
"refresh_token": "..."
}
### Get token from refresh token
#### POST /auth/refresh_token
**Request**
{
"refresh_token": "..."
}
**Response**
{
"token_type": "Bearer",
"expires_in": 31536000,
"access_token": "..."
}
### Get user details
#### GET /me
`Authorization: Bearer <token>`
**Response**
{
"phone": "772754541",
"state": 1,
"encoded_id": "QxomeWjBOLM8A5G",
"secret": "$2y$10$SBXy823s5haIfV3ZmZmpZOo77JATz31Br4rzR6bcO4ZikBpmgCyua"
}
### Update user
#### POST /me
`Authorization: Bearer <token>`
**Request**
{
"state": 1
}
**Response**
{
"success": true
}
### Add/Update user's public key
#### POST /me/public_key
**Request**
{
"public_key": "..."
}
**Response**
{
"success": true
}
### Get token for encounter submission
#### GET /me/encounter_submission_token
**Repose**
{
"token": "..."
}
### Get public key for encryption
#### GET /meta/public_key
**Response**
{
"public_key": "..."
}
### Get available health states
#### GET /meta/health_states
`Authorization: Bearer <token>`
**Response**
{
"health_states": [
{"id": 1, "label_EN": "Normal"},
{"id": 1, "label_EN": "Under self quarantine"},
{"id": 1, "label_EN": "Tested - negative"},
{"id": 1, "label_EN": "Tested - positive"}
]
}
### Submit data about encounters
#### POST {endpoint}
`Authorization: Bearer <token>`
**Request**
{
"PartitionKey": "25ebdc72-7b96-4f47-9a55-1237f976cb86",
"Data": [
{
"exposed_by": 0,
"time": 1585842872273,
"exposedTo": [
{
"user_id": "22BF6D0F0FD92CC0959D",
"time": "26430553",
"signature": "6096974128b5b1a1fefa51c1146663a418f61c59",
"distance": "-55"
}
]
},
{
"exposed_by": 0,
"time": 1585842890567,
"exposedTo": [
{
"user_id": "22BF6D0F0FD92CC0959D",
"time": "26430553",
"signature": "6096974128b5b1a1fefa51c1146663a418f61c59",
"distance": "-53"
}
]
},
{
"exposed_by": 0,
"time": 1585842844494,
"exposedTo": [
{
"user_id": "22BF6D0F0FD92CC0959D",
"time": "26430553",
"signature": "6096974128b5b1a1fefa51c1146663a418f61c59",
"distance": "-54"
}
]
},
{
"exposed_by": 0,
"time": 1585842994423,
"exposedTo": [
{
"user_id": "22BF6D0F0FD92CC0959D",
"time": "26430553",
"signature": "6096974128b5b1a1fefa51c1146663a418f61c59",
"distance": "-52"
}
]
},
{
"exposed_by": 0,
"time": 1585842679918,
"exposedTo": [
{
"user_id": "22BF6D0F0FD92CC0959D",
"time": "26430553",
"signature": "6096974128b5b1a1fefa51c1146663a418f61c59",
"distance": "-58"
}
]
},
{
"exposed_by": 0,
"time": 1585842634878,
"exposedTo": [
{
"user_id": "22BF6D0F0FD92CC0959D",
"time": "26430553",
"signature": "6096974128b5b1a1fefa51c1146663a418f61c59",
"distance": "-56"
}
]
},
{
"exposed_by": 0,
"time": 1585842949460,
"exposedTo": [
{
"user_id": "22BF6D0F0FD92CC0959D",
"time": "26430553",
"signature": "6096974128b5b1a1fefa51c1146663a418f61c59",
"distance": "-57"
}
]
},
{
"exposed_by": 0,
"time": 1585842799449,
"exposedTo": [
{
"user_id": "22BF6D0F0FD92CC0959D",
"time": "26430553",
"signature": "6096974128b5b1a1fefa51c1146663a418f61c59",
"distance": "-59"
}
]
},
{
"exposed_by": 0,
"time": 1585842754484,
"exposedTo": [
{
"user_id": "22BF6D0F0FD92CC0959D",
"time": "26430553",
"signature": "6096974128b5b1a1fefa51c1146663a418f61c59",
"distance": "-58"
}
]
}
]
}
**Response**
{
"success": true
}
### Check if app update is required
#### POST /meta/app_update
**Request**
{
"platfomr": "ios|android",
"version": "1.0.0"
}
**Response**
{
"update_required": false
}
### Submit support request
#### POST me/support_requests
{
"name": "Sahan",
"number": "772754541",
"nic": "5454564",
"address": "123 main st\ncolombo",
"request": "Help!",
"category": "Grocery"
}
### Get support request quota
#### GET me/support_requests/quota
{
"daily_submitted": 1,
"limit_met": true,
"remaining": 0
}
## Admin
### Query support requests
Parameters
- `status`: 1 = open, 0 = closed `?status=0`, by default all results are returned
- `page`: paginating result `?page=1`
- `limit`: default to 100
- `sort`: default to asc (asc|desc)
#### GET /admin/support_requests
**Response**
{
"data": [...],
"total": "200"
}
### Close a support request
#### POST /admin/support_requests/{id}/close
# Internal APIs
## Query users by encoded id
#### POST /admin/users/query
**Testing token** - bafc1dec2abfc3aa2eb326f8881c6f6a
`Authorization: Bearer <token>`
*Request*
{
"encoded_ids": [
"GNnrgKLday2Md8o",
"GNnrgKLday2Md8o",
"GNnrgKLday2Md8o",
"GNnrgKLday2Md8o",
"GNnrgKLday2Md8o",
"GNnrgKLday2Md8o"
]
}
*Response*
{
"users": [
{
"encoded_id": "GNnrgKLday2Md8o",
"phone": "772729382",
"state": "normal",
"created_at": ""
},
{
"encoded_id": "GNnrgKLday2Md8o",
"phone": "772729382",
"state": "normal",
"created_at": ""
},
{
"encoded_id": "GNnrgKLday2Md8o" //no user found
}
]
}