> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.claw-ops.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.claw-ops.com/_mcp/server.

# 카카오 채널 연결

POST https://api.claw-ops.com/v1/accounts/{accountId}/kakao/channels
Content-Type: application/json

담당자 휴대전화로 받은 인증번호로 채널 연결을 완료합니다. **먼저 인증번호 요청을 호출해야 합니다.**

앞 단계에서 보낸 `searchId` 와 `phoneNumber` 를 여기서 다시 보냅니다 — 서버는 등록 도중 상태를 저장하지 않습니다
(미완료 상태의 담당자 전화번호를 남기지 않기 위해서입니다).

**멱등입니다.** 이미 이 계정에 연결된 채널이면 인증번호를 소모하지 않고 기존 연결을 `200` 으로 돌려줍니다.
새로 연결된 경우에만 `201` 입니다. 다른 계정에 이미 연결된 채널이면 멱등이 아니라 충돌이므로 `409` 입니다.

**타임아웃되면 이 요청을 다시 보내지 마세요.** 이미 연결에 성공했을 수 있어 중복 등록을 시도하게 됩니다.
대신 채널 목록이나 상세 조회로 실제 등록 여부를 확인한 뒤 결과를 확정하세요.

Reference: https://docs.claw-ops.com/api-레퍼런스/claw-ops-api/kakao-channels/create-kakao-channel

## Authentication

- `Authorization` header (bearer token, required) — API Key를 Bearer 토큰으로 전달

## Request

### Path parameters

- `accountId` (string, required) — 계정 ID

### Body (application/json)

- `searchId` (string, required) — 카카오 채널 검색용 ID. `@` 를 붙여 보내도 떼어내고 처리합니다.
- `phoneNumber` (string, required) — 인증번호를 받은 담당자 휴대전화번호. 하이픈·+82 형태 모두 허용됩니다.
- `categoryCode` (string, required) — 채널 업종 카테고리 코드. 채널 카테고리 조회 응답의 `code` 를 그대로 보냅니다.
- `token` (string, required) — 담당자 휴대전화로 받은 인증번호. 저장하지 않고 확인에만 사용합니다.

## Response

### 200

이미 이 계정에 연결된 채널 — 기존 연결을 그대로 반환(멱등)

- `id` (string, optional) — ClawOps 채널 리소스 ID. 템플릿 조회와 발송 요청에 이 값을 사용합니다.
- `searchId` (string, optional) — 카카오 채널 검색용 ID. **`@` 없는 형태**로 저장·응답됩니다(`@` 를 붙여 보내도 떼어냅니다). **채널 소유자가 카카오 비즈니스에서 바꿀 수 있는 값이므로 연동 키로 쓰지 마세요** — 키는 `id` 입니다.
- `name` (string, optional) — 카카오 채널 이름
- `categoryCode` (string, optional) — 채널 업종 카테고리 코드. 값 목록은 채널 카테고리 조회로 받습니다.
- `status` (enum, optional) — `connected` = 연결 완료. `needs_attention` = 연결 기록은 있으나 카카오 채널 상태를 확인하지 못한 상태입니다 (채널이 실제로 끊겼을 수도, 일시적인 조회 실패일 수도 있습니다). 상세 조회를 다시 호출하면 재확인합니다.
  - Allowed values: `connected`, `needs_attention`
- `managerPhoneMasked` (string, optional, nullable) — 채널 담당자 휴대전화번호(마스킹). 원문은 저장하지 않으므로 응답에도 마스킹된 값만 나갑니다.
- `connectedAt` (datetime, optional) — 채널이 이 계정에 연결된 시각
- `syncedAt` (datetime, optional, nullable) — 카카오 채널 상태를 마지막으로 확인한 시각. null 이면 연결 이후 한 번도 확인하지 않은 상태입니다.
- `createdAt` (datetime, optional)
- `updatedAt` (datetime, optional)

### 201

채널 연결 성공

- `id` (string, optional) — ClawOps 채널 리소스 ID. 템플릿 조회와 발송 요청에 이 값을 사용합니다.
- `searchId` (string, optional) — 카카오 채널 검색용 ID. **`@` 없는 형태**로 저장·응답됩니다(`@` 를 붙여 보내도 떼어냅니다). **채널 소유자가 카카오 비즈니스에서 바꿀 수 있는 값이므로 연동 키로 쓰지 마세요** — 키는 `id` 입니다.
- `name` (string, optional) — 카카오 채널 이름
- `categoryCode` (string, optional) — 채널 업종 카테고리 코드. 값 목록은 채널 카테고리 조회로 받습니다.
- `status` (enum, optional) — `connected` = 연결 완료. `needs_attention` = 연결 기록은 있으나 카카오 채널 상태를 확인하지 못한 상태입니다 (채널이 실제로 끊겼을 수도, 일시적인 조회 실패일 수도 있습니다). 상세 조회를 다시 호출하면 재확인합니다.
  - Allowed values: `connected`, `needs_attention`
- `managerPhoneMasked` (string, optional, nullable) — 채널 담당자 휴대전화번호(마스킹). 원문은 저장하지 않으므로 응답에도 마스킹된 값만 나갑니다.
- `connectedAt` (datetime, optional) — 채널이 이 계정에 연결된 시각
- `syncedAt` (datetime, optional, nullable) — 카카오 채널 상태를 마지막으로 확인한 시각. null 이면 연결 이후 한 번도 확인하지 않은 상태입니다.
- `createdAt` (datetime, optional)
- `updatedAt` (datetime, optional)

## Examples

### Example 1

**Request**

```json
{
  "searchId": "example",
  "phoneNumber": "010-1234-5678",
  "categoryCode": "00100010001",
  "token": "394812"
}
```

**Response**

```json
{
  "id": "clx9kak0001",
  "searchId": "example",
  "name": "러너스 고객센터",
  "categoryCode": "00100010001",
  "status": "connected",
  "managerPhoneMasked": "010-****-5678",
  "connectedAt": "2024-01-15T09:30:00Z",
  "syncedAt": "2024-01-15T09:30:00Z",
  "createdAt": "2024-01-15T09:30:00Z",
  "updatedAt": "2024-01-15T09:30:00Z"
}
```

**SDK Code**

```python
import requests

url = "https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels"

payload = {
    "searchId": "example",
    "phoneNumber": "010-1234-5678",
    "categoryCode": "00100010001",
    "token": "394812"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"searchId":"example","phoneNumber":"010-1234-5678","categoryCode":"00100010001","token":"394812"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels"

	payload := strings.NewReader("{\n  \"searchId\": \"example\",\n  \"phoneNumber\": \"010-1234-5678\",\n  \"categoryCode\": \"00100010001\",\n  \"token\": \"394812\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"searchId\": \"example\",\n  \"phoneNumber\": \"010-1234-5678\",\n  \"categoryCode\": \"00100010001\",\n  \"token\": \"394812\"\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"searchId\": \"example\",\n  \"phoneNumber\": \"010-1234-5678\",\n  \"categoryCode\": \"00100010001\",\n  \"token\": \"394812\"\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels', [
  'body' => '{
  "searchId": "example",
  "phoneNumber": "010-1234-5678",
  "categoryCode": "00100010001",
  "token": "394812"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"searchId\": \"example\",\n  \"phoneNumber\": \"010-1234-5678\",\n  \"categoryCode\": \"00100010001\",\n  \"token\": \"394812\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "searchId": "example",
  "phoneNumber": "010-1234-5678",
  "categoryCode": "00100010001",
  "token": "394812"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Example 2

**Request**

```json
{
  "searchId": "example",
  "phoneNumber": "010-1234-5678",
  "categoryCode": "00100010001",
  "token": "394812"
}
```

**Response**

```json
{
  "id": "clx9kak0001",
  "searchId": "example",
  "name": "러너스 고객센터",
  "categoryCode": "00100010001",
  "status": "connected",
  "managerPhoneMasked": "010-****-5678",
  "connectedAt": "2024-01-15T09:30:00Z",
  "syncedAt": "2024-01-15T09:30:00Z",
  "createdAt": "2024-01-15T09:30:00Z",
  "updatedAt": "2024-01-15T09:30:00Z"
}
```

**SDK Code**

```python
import requests

url = "https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels"

payload = {
    "searchId": "example",
    "phoneNumber": "010-1234-5678",
    "categoryCode": "00100010001",
    "token": "394812"
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"searchId":"example","phoneNumber":"010-1234-5678","categoryCode":"00100010001","token":"394812"}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels"

	payload := strings.NewReader("{\n  \"searchId\": \"example\",\n  \"phoneNumber\": \"010-1234-5678\",\n  \"categoryCode\": \"00100010001\",\n  \"token\": \"394812\"\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"searchId\": \"example\",\n  \"phoneNumber\": \"010-1234-5678\",\n  \"categoryCode\": \"00100010001\",\n  \"token\": \"394812\"\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"searchId\": \"example\",\n  \"phoneNumber\": \"010-1234-5678\",\n  \"categoryCode\": \"00100010001\",\n  \"token\": \"394812\"\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels', [
  'body' => '{
  "searchId": "example",
  "phoneNumber": "010-1234-5678",
  "categoryCode": "00100010001",
  "token": "394812"
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"searchId\": \"example\",\n  \"phoneNumber\": \"010-1234-5678\",\n  \"categoryCode\": \"00100010001\",\n  \"token\": \"394812\"\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "searchId": "example",
  "phoneNumber": "010-1234-5678",
  "categoryCode": "00100010001",
  "token": "394812"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.claw-ops.com/v1/accounts/AC1a2b3c4d/kakao/channels")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```