# Thêm Nhân viên vào Shop bằng OTP

> Đối tác (affiliate) gọi Lấy OTP cho số điện thoại của chủ shop, GHN gửi OTP qua SMS tới số đó, sau đó đối tác gửi OTP này lên đây để tự thêm mình làm nhân viên của shop hiện có của chủ. Đây là bước 2 của luồng affiliate (xem [Lấy OTP](https://developer.ghn.vn/vi/docs/affiliate/get-otp.md)).

## Endpoint

| Môi trường | URL |
| --- | --- |
| Production | `https://online-gateway.ghn.vn/shiip/public-api/v2/shop/affiliateCreateWithShop` |
| Staging | `https://dev-online-gateway.ghn.vn/shiip/public-api/v2/shop/affiliateCreateWithShop` |

**Method**: `POST`

## Headers

| Header | Bắt buộc | Mô tả |
| --- | --- | --- |
| `Content-Type` | Có | `application/json` |
| `Token` | Có | Token của bạn (đối tác), do GHN cấp. Tài khoản của bạn phải đang hoạt động — [lấy token](https://developer.ghn.vn/vi/docs/token/get-token.md) |
| `ShopId` | Không | Chọn ngữ cảnh shop **của chính bạn** (độc lập với `shop_id` trong body); nếu bỏ trống, shop mặc định của tài khoản bạn được dùng. Shop được chọn phải đang hoạt động và thuộc về bạn, nếu không request sẽ bị từ chối |

## Tham số

- **phone** (String): SĐT của chủ shop đã nhận OTP. Phải ứng với một tài khoản GHN đã đăng ký **và** là chủ sở hữu của `shop_id`; nếu không, request sẽ lỗi `CLIENT_NOT_BELONG_OF_SHOP`
- **otp** (String): OTP lấy từ [Lấy OTP](https://developer.ghn.vn/vi/docs/affiliate/get-otp.md). Dùng một lần: bị vô hiệu sau khi gọi thành công. OTP sai hoặc hết hạn sẽ lỗi `OTP_NOT_VALID`
- **shop_id** (Int): Shop hiện có của chủ mà bạn sẽ tham gia làm nhân viên. Phải tồn tại, nếu không request sẽ lỗi `Shop khong ton tai` (shop không tồn tại)
- **language** (String): Ngôn ngữ của `code_message_value` trong response lỗi. Mặc định `vi`.<br>`vi`: Tiếng Việt<br>`en`: Tiếng Anh

## Ví dụ Request

```bash
curl -X POST https://dev-online-gateway.ghn.vn/shiip/public-api/v2/shop/affiliateCreateWithShop \
  -H "Token: 5c1d8a9e-2f4b-11ed-..." \
  -H "ShopId: 92837" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "0987654321",
    "otp": "123456",
    "shop_id": 200996
  }'
```

## Response

### Thành công (HTTP 200)

Nhân viên được thêm luôn là **tài khoản của chính bạn** (tài khoản đứng sau token) — bạn không thể dùng API này để thêm một tài khoản thứ ba bất kỳ. Khi thành công, tài khoản của bạn được cấp bộ quyền member mặc định trên shop của chủ, để bạn vận hành thay họ.

```json
{
  "code": 200,
  "message": "Success",
  "data": null
}
```

### Các trường Response

| Trường | Kiểu | Mô tả |
| --- | --- | --- |
| `code` | Int | Mã HTTP (`200` nếu thành công) |
| `message` | String | Thông báo kết quả (`Success`) |
| `data` | null | Luôn `null` với API này |

### Lỗi — thiếu phone, otp và shop_id (HTTP 400)

_Lấy từ một lần gọi thật trên môi trường Staging._

```json
{
  "code": 400,
  "message": "Key: 'myRequest.Phone' Error:Field validation for 'Phone' failed on the 'required' tag\nKey: 'myRequest.OTP' Error:Field validation for 'OTP' failed on the 'required' tag\nKey: 'myRequest.ShopID' Error:Field validation for 'ShopID' failed on the 'required' tag",
  "data": null,
  "code_message": "USER_ERR_COMMON",
  "code_message_value": "Sai thông tin đầu vào. Vui lòng thử lại."
}
```

> **NOTE**
> Chuỗi thêm nhân viên (thêm bạn làm nhân viên → cấp quyền → vô hiệu OTP) không phải atomic và không có rollback: nếu lỗi ở giữa chừng thì các bước có thể đã được áp dụng một phần dù bạn nhận về lỗi.

## Bảng mã lỗi

| Điều kiện | HTTP | code_message |
| --- | --- | --- |
| Thiếu `phone`, `otp` hoặc `shop_id`, hoặc dữ liệu không hợp lệ | 400 | `USER_ERR_COMMON` |
| `otp` sai hoặc hết hạn | 400 | `OTP_NOT_VALID` |
| Shop không tồn tại (`Shop khong ton tai`) | 400 | — |
| `phone` không phải chủ sở hữu của `shop_id` | 400 | `CLIENT_NOT_BELONG_OF_SHOP` |
| Bạn đã là nhân viên của shop | 400 | `CLIENT_HAVE_EXISTED` |
| Lỗi hệ thống | 500 | `SERVER_ERROR_COMMON` |
