---
# System prepended metadata

title: Betacard API Proposal

---

# 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"
}
```


