# Create Shop by OTP

> The affiliate (partner) calls Get OTP for the shop owner's phone, GHN sends an SMS OTP to that phone, and the affiliate then submits that OTP here to create a new shop owned by that customer. This is step 2 of the affiliate flow (see [Get OTP](https://developer.ghn.vn/en/docs/affiliate/get-otp.md)).

## Endpoint

| Environment | URL |
| --- | --- |
| Production | `https://online-gateway.ghn.vn/shiip/public-api/v2/shop/affiliateCreate` |
| Staging | `https://dev-online-gateway.ghn.vn/shiip/public-api/v2/shop/affiliateCreate` |

**Method**: `POST`

## Headers

| Header | Required | Description |
| --- | --- | --- |
| `Content-Type` | Yes | `application/json` |
| `Token` | Yes | Your (the partner's) token, issued by GHN. Your account must be active — [get a token](https://developer.ghn.vn/en/docs/token/get-token.md) |
| `ShopId` | No | Selects your shop context; when omitted, your account's default shop is used. The resolved shop must be active and belong to you, otherwise the request is rejected |

## Parameters

- **phone** (String): Phone of the shop owner (your customer) who received the OTP. Must resolve to a registered GHN account
- **otp** (String): OTP obtained via [Get OTP](https://developer.ghn.vn/en/docs/affiliate/get-otp.md). Single-use: it is invalidated after a successful call. A wrong or expired OTP fails with `OTP_NOT_VALID`
- **address** (String): Pickup address of the new shop. When empty, GHN falls back to the owner's default shop address, then to your own default shop address
- **district_id** (Int): GHN-internal district code of the new shop, from [Get District](https://developer.ghn.vn/en/docs/master-data/get-district.md). When `0`, same fallback chain as `address`
- **ward_code** (String): GHN-internal ward code of the new shop, from [Get Ward](https://developer.ghn.vn/en/docs/master-data/get-ward.md). When empty, same fallback chain as `address`
- **language** (String): Language of `code_message_value` in error responses. Default `vi`.<br>`vi`: Vietnamese<br>`en`: English

## Request Example

```bash
curl -X POST https://dev-online-gateway.ghn.vn/shiip/public-api/v2/shop/affiliateCreate \
  -H "Token: 5c1d8a9e-2f4b-11ed-..." \
  -H "ShopId: 92837" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "0987654321",
    "otp": "123456",
    "address": "72 Lê Thánh Tôn, P. Bến Nghé, Quận 1, TP. Hồ Chí Minh",
    "district_id": 1444,
    "ward_code": "20308"
  }'
```

## Response

### Success (HTTP 200)

The new shop belongs to your customer, not to you. Its name is server-generated as `<customer name> - <your partner name>` (you cannot choose it). After creation, your own account is automatically added as staff of the new shop with the default member permission set, so you can operate it on the customer's behalf.

```json
{
  "code": 200,
  "message": "Success",
  "data": {
    "client_id": 1234567,
    "shop_id": 200996
  }
}
```

### Response Fields

| Field | Type | Description |
| --- | --- | --- |
| `code` | Int | HTTP code (`200` on success) |
| `message` | String | Result message (`Success`) |
| `data.client_id` | Int | Account ID of the shop owner (your customer, resolved from `phone`) |
| `data.shop_id` | Int | ID of the newly created shop |

### Error — missing phone and otp (HTTP 400)

_Captured from a real Staging-environment call._

```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",
  "data": null,
  "code_message": "USER_ERR_COMMON",
  "code_message_value": "Sai thông tin đầu vào. Vui lòng thử lại."
}
```

> **NOTE**
> The create sequence (create shop → add you as staff → grant permissions → invalidate OTP) is not atomic and has no rollback. A failure part-way (e.g. at the staff-adding step) can leave the shop created even though you receive an error. On error, verify with Get Shop before retrying to avoid duplicate shops.

## Error Codes

| Condition | HTTP | code_message |
| --- | --- | --- |
| Missing `phone` or `otp`, or invalid input | 400 | `USER_ERR_COMMON` |
| Wrong or expired `otp` | 400 | `OTP_NOT_VALID` |
| Phone not registered as a GHN account | 400 | `USER_ERR_COMMON` |
| You are already staff of the resulting shop | 400 | `CLIENT_HAVE_EXISTED` |
| Internal error | 500 | `SERVER_ERROR_COMMON` |
