# Betacard API Proposal
# Base URL
Staging URL: `https://betacard-api.herokuapp.com/api/v1`
# Authenticating Requests
Please include the `Authorization` in your requests like so:
`Authorization: Bearer <TOKEN>`
`TOKEN` can be obtained from the response body when [signing in](#Sign-In).
# Pagination
For endpoints with paginated contents.
The pagination information will be included in the response header like so:
|HEADER|Description|
|--------|---------|
|`X-Page`|Current page|
|`X-Count`|Current specified count|
|`X-Total-Pages`|Total number of pages|
|`X-Total-Records`|Total number of records|
# Error
Every error message conform to this shape
```
{
"message": string;
"code": string;
"errors": [];
"timestamp": string;
"resource": string;
}
```
Example
```
{
"message": "Access Code is not found",
"code": "access_code_not_found",
"errors": [],
"timestamp": "2019-10-18T06:04:53Z",
"resource": "/api/v1/account/verify_signin"
}
```
# Account
### Sign up
*Creates an account for new user*
|Method|Path|
|------|-----------------|
|`POST`|`/account/sign_up`|
Staging URL: https://betacard-api.herokuapp.com/api/v1/account/sign_up
**Request Body**
```
{
"phoneNumber": "+60171122345",
"firstName": "John",
"lastName": "Wick",
"email": "johnwick@hightable.global"
}
```
**Response**
| Status Code | Description|
|------|-----------------|
| **200 OK** | New Account successfully created|
Body
```
{
"id": 5,
"phoneNumber": "+60168028426",
"createdAt": "2019-10-11T02:41:36Z",
"profile": {
"id": 5,
"email": "deojeff@gmail.com",
"isEmailVerified": false,
"firstName": "John",
"lastName": "Wick",
"createdAt": "2019-10-11T02:41:36Z",
"updatedAt": "2019-10-11T02:41:36Z"
}
}
```
| Status Code | Description|
|------|-----------------|
| **400 Bad Request** | Field validation failed|
Body
```
{
"message": "Validation Error",
"code": "validation_error",
"errors": [
{
"field": "phoneNumber",
"code": "is_defined"
},
{
"field": "firstName",
"code": "is_defined"
},
{
"field": "lastName",
"code": "is_defined"
},
{
"field": "email",
"code": "is_defined"
}
],
"timestamp": "2019-10-11T06:38:25Z",
"resource": "/api/v1/sign_up"
}
```
| Status Code | Error | Description |
|------|-----------------|----------|
| **409 Conflict** | `PhoneNumberInUseException` | Phone Number already in use |
Body
```
{
"message": "Phone Number Already In Use",
"code": "phone_number_in_use",
"errors": [],
"timestamp": "2019-10-11T06:47:29Z",
"resource": "/api/v1/sign_up"
}
```
| Status Code | Error | Description |
|------|-----------------|----------|
| **409 Conflict** | `EmailAlreadyInUseException` | Email already in use |
Body
```
{
"message": "Email Already In Use",
"code": "email_already_in_use",
"errors": [],
"timestamp": "2019-10-11T08:54:32Z",
"resource": "/api/v1/sign_up"
}
```
### Sign In
*Creates a sign in request*
|Method|Path|
|------|------------------|
|`POST`| `/account/sign_in`|
**Request Body**
```
{
"phoneNumber": "+60171122345"
}
```
**Response**
| Status Code | Description|
|------|-----------------|
| **204 No Content** | Verification SMS sent|
Body
```
{ }
```
| Status Code | Error | Description |
|------|-----------------|----------|
| **404 Not Found** | `PhoneNumberInvalidException` | Phone Number does not exist. |
Body
```
{
"message": "Phone Number does not exist.",
"code": "phone_number_not_valid",
"errors": [],
"timestamp": "2019-10-15T09:24:01Z",
"resource": "/api/v1/signin"
}
```
---
### Verify Sign In Request
`POST /account/verify_sign_in`
*Verifies sign in request using the code sent via SMS*
**Request Body**
```
{
"phoneNumber": "+60171122345",
"code": "1234"
}
```
**Response**
| Status Code | Description|
|------|-----------------|
| **200 OK** | Account successfully verified|
Body
```
{
"lastUsedAt": "2019-11-12T09:33:59.756Z",
"user": {
"createdAt": "2019-11-12T03:19:16Z",
"updatedAt": "2019-11-12T03:19:16Z",
"id": 3,
"phoneNumber": "+84912345678",
"profile": {
"createdAt": "2019-11-12T03:19:16Z",
"updatedAt": "2019-11-12T03:19:16Z",
"id": 3,
"email": "testing@gmail.com",
"firstName": "John",
"lastName": "Wick"
}
},
"userAccessCode": {
"id": 31,
"code": "7028",
"recipient": "+84912345678",
"expiresAt": "2019-11-12T09:59:37Z",
"usedAt": null,
"invalidatedAt": null,
"user": {
"createdAt": "2019-11-12T03:19:16Z",
"updatedAt": "2019-11-12T03:19:16Z",
"id": 3,
"phoneNumber": "+84912345678"
}
},
"token": "vPXegfWzQ0W4p33FFS0I17GrHhc1Zxxx",
"invalidatedAt": null,
"id": 2
}
```
| Status Code | Description|
|------|-----------------|
| **400 Bad Request** | Field validation failed|
Body
```
{
"message": "Validation Error",
"code": "validation_error",
"errors": [
{
"field": "phoneNumber",
"code": "is_defined"
},
{
"field": "code",
"code": "is_defined"
}
],
"timestamp": "2019-10-11T06:38:25Z",
"resource": "/api/v1/verify_signin"
}
```
| Status Code | Description|
|------|-----------------|
| **404 Not Found** | Access code not found |
Body
```
{
"message": "Access Code is not found",
"code": "access_code_not_found",
"errors": [],
"timestamp": "2019-10-16T07:38:51Z",
"resource": "/api/v1/verify_signin"
}
```
| Status Code | Description|
|------|-----------------|
| **406 Unprocessable Entity** | Access Code has expired|
Body
```
{
"message": "Access Code has expired",
"code": "access_code_has_expired",
"errors": [],
"timestamp": "2019-10-16T07:38:51Z",
"resource": "/api/v1/verify_signin"
}
```
| Status Code | Description|
|------|-----------------|
| **406 Unprocessable Entity** | Access Code has been used|
Body
```
{
"message": "Access Code has been used",
"code": "access_code_has_been_used",
"errors": [],
"timestamp": "2019-10-16T07:38:51Z",
"resource": "/api/v1/verify_signin"
}
```
### Sign Out
`POST /account/signout`
*Sign out user by verifying token*
**Request Body**
```
{
"token": "$2a$12$z3ZsVNDysDRpF5blkCcAJelJWwi9DyXX94xm5qIgriKVsqpRMdmY.",
}
```
**Response**
| Status Code | Description|
|------|-----------------|
| **200 OK** | Account successfully logged out|
Body
```
{
"id": 1,
"token": "$2a$12$QHwkV/aZwrozx0jD2ghGnOfwHtP8QAQJgAhAxumHCQtM.2IEpwry6",
"lastUsedAt": "2019-10-16T04:55:19Z",
"invalidatedAt": "2019-10-17T10:10:54Z",
"user": {
"id": 1,
"phoneNumber": "+60164104864",
"createdAt": "2019-10-15T04:13:31Z"
},
"userAccessCode": {
"id": 3,
"code": "4960",
"recipient": "+60164104864",
"expiresAt": "2019-10-16T05:13:48Z",
"usedAt": "2019-10-16T04:55:19Z",
"invalidatedAt": "2019-10-16T05:01:38Z"
}
}
```
| Status Code | Description|
|------|-----------------|
| **404 Not Found** | User session cannot be found |
Body
```
{
"message": "User session cannot be found",
"code": "user_session_not_found",
"errors": [],
"timestamp": "2019-10-17T10:13:02Z",
"resource": "/api/v1/account/signout"
}
```
| Status Code | Description|
|------|-----------------|
| **400 Bad Request** | Field validation failed|
Body
```
{
"message": "Validation Error",
"code": "validation_error",
"errors": [
{
"field": "token",
"code": "is_defined"
}
],
"timestamp": "2019-10-17T10:15:34Z",
"resource": "/api/v1/signout"
}
```
# Card Theme
### Create Card Theme
*Creates a new theme for user*
|Method|Path|
|------|-----------------|
|`POST`|`/card_themes`|
**Request Body**
```
{
"title": "my first theme",
"scheme": {
// Contains all the design and layout information
},
}
```
**Response**
| Status Code | Description|
|------|-----------------|
| **200 OK** | New theme successfully created|
Body
```
{
"title": "my first theme",
"id": 1
"scheme": {},
"user": {
"createdAt": "2019-11-12T09:07:14Z",
"updatedAt": "2019-11-12T09:07:14Z",
"id": 1,
"phoneNumber": "+601349724954"
},
"createdAt": "2019-12-24T07:27:44Z",
"updatedAt": "2019-12-24T07:27:44Z",
}
```
| Status Code | Description|
|------|-----------------|
| **400 Bad Request** | Field validation failed|
Body
```
{
"message": "Validation Error",
"code": "validation_error",
"errors": [
{
"field": "title",
"code": "is_defined"
},
{
"field": "scheme",
"code": "is_defined"
},
],
"timestamp": "2019-10-11T06:38:25Z",
"resource": "/api/v1/card_themes"
}
```
### Get list of Card Themes
Retrieves a paginated list of Card Theme sorted by creation time
|Method|Path|
|------|-----------------|
|`GET`|`/card_themes/me`|
**Response**
```
[
{
"id": 1,
"title": "my first theme",
"createdAt": "2019-12-24T07:27:44Z",
"updatedAt": "2019-12-24T07:27:44Z",
"scheme": {},
"user": {
"id": 1,
"createdAt": "2019-11-12T09:07:14Z",
"updatedAt": "2019-11-12T09:07:14Z",
"phoneNumber": "+601119724552"
}
},
{
"id": 2,
"title": "my second theme",
"createdAt": "2019-12-24T07:27:55Z",
"updatedAt": "2019-12-24T07:27:55Z",
"scheme": {},
"user": {
"id": 1,
"createdAt": "2019-11-12T09:07:14Z",
"updatedAt": "2019-11-12T09:07:14Z",
"phoneNumber": "+601119724552"
}
}
]
```
### Get One Card Theme By ID
Retrieves a single theme by id
|Method|Path|
|------|-----------------|
|`GET`|`/card_themes/:id`|
**Response**
| Status Code | Description|
|------|-----------------|
| **200 OK** | Card theme retrieved successfully |
Body
```
{
"id": 2,
"title": "my second theme",
"createdAt": "2019-12-24T07:27:55Z",
"updatedAt": "2019-12-24T07:27:55Z",
"scheme": {},
"user": {
"id": 1,
"createdAt": "2019-11-12T09:07:14Z",
"updatedAt": "2019-11-12T09:07:14Z",
"phoneNumber": "+601119724552"
}
}
```
| Status Code | Description|
|------|-----------------|
| **404 Not Found** | Card Theme Not Found |
Body
```
{
"message": "Card Theme Not Found",
"code": "card_theme_not_found",
"errors": [],
"timestamp": "2019-10-16T07:38:51Z",
"resource": "/api/v1/card_themes/:id"
}
```
### Delete Card Theme
*Deletes a Card Theme based on given ID*
|Method|Path|
|------|-----------------|
|`DELETE`|`/card_themes/:id`|
**Response**
| Status Code | Description|
|------|-----------------|
| **204 No Content** | Card Theme Successfully Deleted|
| Status Code | Description|
|------|-----------------|
| **404 Not Found** | Card Theme Not Found |
Body
```
{
"message": "Card Theme Not Found",
"code": "card_theme_not_found",
"errors": [],
"timestamp": "2019-10-16T07:38:51Z",
"resource": "/api/v1/card_themes/:id
}
```
# Card
### Create Card
*Creates a new card for user*
|Method|Path|
|------|-----------------|
|`POST`|`/cards`|
Insert bearer token for authorization.
**Request Body**
```
{
"title": "first card",
"scheme": {
// Contains all the design and layout information
},
"fieldData": {
// Contains all the labels and values
},
"type": "personal",
"isFavorite": false
}
```
**Response**
| Status Code | Description|
|------|-----------------|
| **200 OK** | New card successfully created|
Body
```
{
"id": 1,
"type": "personal",
"scheme": {
//Contains all the design and layout information
},
"fieldData": {
//Contains all the labels and values
},
"details": {
"id": 1,
"title": "my first card",
"isFavorite": false,
},
"user": {
"id": 1,
"phoneNumber": "+60164104864",
"createdAt": "2019-10-15T04:13:31Z"
},
"updatedAt": "2019-10-17T11:51:46Z",
"createdAt": "2019-10-17T11:51:46Z"
}
```
| Status Code | Description|
|------|-----------------|
| **404 Not Found** | User Not Found |
Body
```
{
"message": "User Not Found",
"code": "user_not_found",
"errors": [],
"timestamp": "2019-10-16T07:38:51Z",
"resource": "/api/v1/cards
}
```
### Get List of Cards
*Get a list of user's card*
|Method|Path|
|------|-----------------|
|`GET`|`/cards/me`|
Insert bearer token for authorization.
**Response**
| Status Code | Description|
|------|-----------------|
| **200 OK** | Get all user's card succesfully |
Body
```
[
{
"id": 1,
"type": "personal",
"scheme": {
//Contains all the design and layout information
},
"fieldData": {
//Contains all the labels and values
},
"details": {
"id": 1,
"title": "my first card",
"isFavorite": false,
},
"user": {
"id": 1,
"phoneNumber": "+60164104864",
"createdAt": "2019-10-15T04:13:31Z"
},
"updatedAt": "2019-10-17T11:51:46Z",
"createdAt": "2019-10-17T11:51:46Z"
},
{
"id": 2,
"type": "personal",
"scheme": {
//Contains all the design and layout information
},
"fieldData": {
//Contains all the labels and values
},
"details": {
"id": 2,
"title": "my second card",
"isFavorite": false,
},
"user": {
"id": 1,
"phoneNumber": "+60164104864",
"createdAt": "2019-10-15T04:13:31Z"
},
"updatedAt": "2019-10-17T11:51:46Z",
"createdAt": "2019-10-17T11:51:46Z"
}
]
```
### Get One Card By ID
Retrieves a single theme by id
|Method|Path|
|------|-----------------|
|`GET`|`/cards/:id`|
**Response**
| Status Code | Description|
|------|-----------------|
| **200 OK** | Card theme retrieved successfully |
Body
```
{
"id": 1,
"type": "personal",
"scheme": {
//Contains all the design and layout information
},
"fieldData": {
//Contains all the labels and values
},
"details": {
"id": 1,
"title": "my first card",
"isFavorite": false,
},
"user": {
"id": 1,
"phoneNumber": "+60164104864",
"createdAt": "2019-10-15T04:13:31Z"
},
"updatedAt": "2019-10-17T11:51:46Z",
"createdAt": "2019-10-17T11:51:46Z"
}
```
| Status Code | Description|
|------|-----------------|
| **404 Not Found** | Card Not Found |
Body
```
{
"message": "Card Not Found",
"code": "card_not_found",
"errors": [],
"timestamp": "2019-12-24T09:00:40Z",
"resource": "/api/v1/cards/:id"
}
```
### Update Card
Updates a single card by ID
|Method|Path|
|------|-----------------|
|`PUT`|`/cards/:id`|
Insert bearer token for authorization.
**Request**
```
{
"title": "my first card",
"scheme": {},
"fieldData": {},
"isFavorite": true
}
```
**Response**
| Status Code | Description|
|------|-----------------|
| **200 OK** | Card updated successfully |
Body
```
{
"id": 1,
"type": "personal",
"scheme": {
//Contains all the design and layout information
},
"fieldData": {
//Contains all the labels and values
},
"details": {
"id": 1,
"title": "my first card",
"isFavorite": false,
},
"user": {
"id": 1,
"phoneNumber": "+60164104864",
"createdAt": "2019-10-15T04:13:31Z"
},
"updatedAt": "2019-10-17T11:51:55Z",
"createdAt": "2019-10-17T11:51:46Z"
}
```
| Status Code | Description|
|------|-----------------|
| **404 Not Found** | Card id not found |
Body
```
{
"message": "Card id cannot found",
"code": "card_id_not_found",
"errors": [],
"timestamp": "2019-10-16T07:38:51Z",
"resource": "/api/v1/card/"
}
```
### Delete Card
Delete a single card by id
|Method|Path|
|------|-----------------|
|`DELETE`|`/cards/:id`|
Insert bearer token for authorization.
**Response**
| Status Code | Description|
|------|-----------------|
| **204 No Content** | Card deleted successfully |
| Status Code | Description|
|------|-----------------|
| **404 Not Found** | Card not found |
Body
```
{
"message": "Card cannot be found",
"code": "card_not_found",
"errors": [],
"timestamp": "2019-10-16T07:38:51Z",
"resource": "/api/v1/card/"
}
```
### Upload image
upload an image for card and card theme
|Method|Path|
|------|-----------------|
|`POST`|`/image_uploads`|
Insert bearer token for authorization.
**Request**
```
content type = form data
file = image binary
```
**Response**
| Status Code | Description|
|------|-----------------|
| **200 OK** | Image uploaded successfully |
Body
```
{
"originalName": "phone.jpg",
"mimeType": "image/jpeg",
"url": "https://betacard.s3.amazonaws.com/2020/01/06/1b449c90-6e65-471a-807c-c0e5cf95dab0.jpg",
"user": {
"createdAt": "2019-11-12T09:07:14Z",
"updatedAt": "2019-11-12T09:07:14Z",
"id": 4,
"phoneNumber": "+601119724552"
},
"id": 1,
"createdAt": "2020-01-06T03:44:22Z"
}
```