> ## Documentation Index
> Fetch the complete documentation index at: https://docs.telloai.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 통화 생성

> 에이전트나 크루를 지정해 발신하고, 멱등 키로 중복 발신을 막아요.

## 할 수 있는 일

운영에 반영한 에이전트나 크루로 전화를 걸어요. 통화마다 달라지는 이름·예약 정보는
`variables`로 넘겨요. 대상의 문안과 설정은 운영에 반영된 판을 사용해요.

```http theme={null}
POST https://api.telloai.io/v1/calls
```

## 헤더

| 이름 | 필수 | 설명 |
| - | - | - |
| `Authorization` | 필수 | `Bearer <API_KEY>` |
| `Content-Type` | 필수 | `application/json` |
| `Idempotency-Key` | 선택 | 중복 발신 방지 키. 1\~255자이고 쉼표를 넣을 수 없어요. 헤더는 한 번만 보내세요 |

## 본문

| 필드 | 타입 | 필수 | 설명 |
| - | - | - | - |
| `agentId` | 양의 정수 또는 숫자 문자열 | 둘 중 하나 | 통화에 쓸 에이전트 id |
| `crewId` | 양의 정수 또는 숫자 문자열 | 둘 중 하나 | 통화에 쓸 크루 id |
| `to` | 문자열 | 필수 | 전화를 걸 수신번호. E.164 형식(`+821012345678`)으로 보내세요 |
| `variables` | 객체 | 선택 | 통화 시작 값. 크루가 요구하는 값은 필수예요 |

**`agentId`와 `crewId` 중 정확히 하나만 넣으세요.** 둘 다 없거나 둘 다 있으면
`400 target_required`가 와요. `null`은 지정하지 않은 것으로 봐요. 기본 대상을 자동으로
고르지 않아요. id는 [대상 목록](https://docs.telloai.io/developer/rest/targets.md)에서 확인해요.

다른 계정의 대상과 삭제된 대상은 없는 대상으로 처리해요. 에이전트는 배포 상태여야 하고,
에이전트·크루 모두 운영에 반영된 판이 있어야 해요.

### 통화 시작 값

`variables`는 이름을 키로, 값을 문자열이나 유한한 숫자로 넣는 JSON 객체예요.

* 최대 **50개** 이름을 보낼 수 있어요.
* 숫자 값은 문자열로 바뀌고, 값의 앞뒤 공백은 제거돼요. 그 뒤 길이가 값마다 **200자 이하**여야 해요.
* 배열·불리언·객체·`null`을 개별 값으로 넣을 수 없어요.
* 이름은 비어 있으면 안 되고 점(`.`)을 넣을 수 없어요. 점이 있는 이름은 시스템 변수용이에요.
  그 밖의 이름 규칙은 [프롬프트 변수](https://docs.telloai.io/agents/variables.md)를 참고하세요.
* `variables` 자체를 생략하거나 `null` 또는 빈 객체로 보내면 통화 시작 값이 없는 것으로 봐요.

```json theme={null}
{
  "agentId": "12",
  "to": "+821012345678",
  "variables": {
    "고객명": "홍길동",
    "예약일": "2026-10-21",
    "인원": 2
  }
}
```

### 크루가 요구하는 값

크루의 멤버 지시문, **진입 멤버의 첫 인사**, 전환 멘트에서 쓰는 통화 시작 값은 발신 전에
채워야 해요. 날짜·시각·고객번호처럼 시스템이 채우는 값과 전환에서 전달할 값은 요구하지
않아요. 다만 진입 멤버의 첫 인사에 쓰는 값은 나중의 전환으로 채울 수 없으므로 시작할 때
필요해요. 도구 URL의 변수는 이 필수 검사에 포함하지 않아요.

필요한 이름이 빠졌거나 값이 공백뿐이면 **발신하지 않고** `422 missing_variables`를 돌려줘요.
`data.missingVariables`의 이름을 채워 같은 멱등 키로 다시 요청하세요. 대상 목록에는 필수
변수 목록이 포함되지 않아요.

```json 필수 값 누락 예시 theme={null}
{
  "statusCode": 422,
  "message": "Required start variables are missing: 고객명",
  "error": "missing_variables",
  "data": {
    "missingVariables": ["고객명"]
  }
}
```

## 예제

```bash 에이전트로 발신 theme={null}
curl --request POST "https://api.telloai.io/v1/calls" \
  --header "Authorization: Bearer <API_KEY>" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: booking-20261020-001" \
  --data '{"agentId":"12","to":"+821012345678","variables":{"고객명":"홍길동"}}'
```

```bash 크루로 발신 theme={null}
curl --request POST "https://api.telloai.io/v1/calls" \
  --header "Authorization: Bearer <API_KEY>" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: booking-20261020-002" \
  --data '{"crewId":"34","to":"+821012345678","variables":{"고객명":"홍길동","예약일":"2026-10-21"}}'
```

## 결과

성공하면 **`201 Created`와 통화 객체**가 와요. 별도의 `data` 봉투는 없어요.

```json 201 예시 theme={null}
{
  "id": "c_12345",
  "status": "dialing",
  "direction": "outbound",
  "source": "api",
  "agentId": "12",
  "crewId": null,
  "createdAt": "2026-10-20T01:00:00.000Z",
  "startedAt": null,
  "endedAt": null,
  "durationSeconds": null,
  "endReason": null,
  "transcript": null,
  "summary": null,
  "creditCharged": null
}
```

각 필드와 상태는 [통화 상세](https://docs.telloai.io/developer/rest/get-call.md)에 있어요. `201`은 발신을 수락했다는
뜻이고, 상대가 받았다는 보장은 아니에요. 응답 시점에 이미 상태가 바뀌어 있을 수도 있어요.
응답을 받은 뒤 HTTP 연결을 닫아도 통화는 계속돼요.

## 중복 발신 방지

네트워크 재시도나 작업 재실행이 있다면 처음 요청부터 `Idempotency-Key`를 붙이세요.
통화 한 건을 만들려는 작업마다 고유한 값을 쓰고, **그 작업을 재시도할 때는 같은 키**를 써요.
키는 계정 범위로 관리돼요. 같은 계정의 다른 API 키를 쓰더라도 멱등 키의 범위는 같아요.
[통화 전환](https://docs.telloai.io/developer/rest/transfer-call.md#중복-전환-방지)도 같은 키 공간을 써요. 전환에 쓴 키를
통화 생성에 다시 쓰면 다른 요청으로 보고 `409 idempotency_key_reused`를 돌려줄 수 있어요.

| 상황 | 동작 |
| - | - |
| `201`로 발신 수락 | 응답 상태 코드와 본문을 24시간 저장해요 |
| `502 call_outcome_unknown` | 발신됐을 수 있으므로 이 응답도 24시간 저장해요 |
| 저장된 키 + 정규화 후 같은 요청 | 저장된 응답을 그대로 돌려주고 새로 발신하지 않아요 |
| 저장됐거나 처리 중인 키 + 다른 요청 | `409 idempotency_key_reused`가 와요 |
| 같은 키의 같은 요청이 아직 처리 중 | `409 idempotency_in_progress`가 와요. 잠시 뒤 같은 키로 확인하세요 |
| 그 밖의 발신 전 거절(`4xx`·`5xx`) | 거절 응답을 저장하지 않아요. 원인을 해소한 뒤 같은 키로 다시 시도할 수 있어요 |

같은 요청인지는 본문 글자 그대로가 아니라 **검증·정규화한 값**으로 비교해요. 대상 id의
`12`와 `"12"`, `to`의 앞뒤 공백, 변수 키 순서, 숫자 변수 `2`와 문자열 `"2"`, 변수 값의 앞뒤
공백 차이는 정규화 뒤 같으면 같은 요청이에요.

저장된 `201`은 **처음 응답의 재생**이지 최신 상태 조회가 아니에요. 최신 상태는 받은 `id`로
[통화 상세](https://docs.telloai.io/developer/rest/get-call.md)를 조회하세요. 24시간이 지난 키는 새 요청으로 처리될
수 있으니, 지난 작업을 다시 발신하는 용도로 재사용하지 마세요.

> [!WARNING]
>
> 발신은 수락됐지만 멱등 응답을 저장하지 못한 경우, 키는 잠시 `idempotency_in_progress`로
> 남을 수 있어요. 5분 뒤에는 같은 키도 새 요청으로 처리돼 중복 발신될 수 있어요.
> 이미 `201`을 받았다면 생성 요청을 다시 보내지 말고 받은 통화 id를 조회하세요.
> 결과를 모르는 상태에서 `409`가 계속되면 목록을 확인하고, 발신 여부가 불분명하면 지원팀에
> 문의하세요.

> [!WARNING]
>
> `502 call_outcome_unknown`은 요청의 결과를 확인하지 못했다는 뜻이에요. 통화가 이미
> 시작됐을 수 있어요. 같은 키를 재시도하면 저장된 `502`가 다시 오고 추가 발신은 하지 않아요.
> **먼저 [통화 목록](https://docs.telloai.io/developer/rest/list-calls.md)에서 대상과 생성 시각으로 확인하세요.**
> 발신 여부를 확인하기 전에는 새 키로 재발신하지 마세요.

키를 생략하면 이 24시간 응답 재생을 사용할 수 없어요. 같은 번호로 현재 발신 중인 통화를
막는 검사만으로는 작업 재실행에 따른 중복 발신을 막을 수 없어요.

## 오류

입력·인증·대상·필수 변수·크레딧 조건을 통과한 뒤 발신해요. 회선이 가득 찼거나 크레딧이
부족한 것처럼 발신 전에 거절된 요청은 조건을 해결하고 같은 키로 재시도할 수 있어요.
전체 HTTP 상태 코드와 대처 방법은 [REST 오류](https://docs.telloai.io/developer/rest/errors.md)를 보세요.

## 관련 문서

* [통화 목록](https://docs.telloai.io/developer/rest/list-calls.md)
* [통화 상세](https://docs.telloai.io/developer/rest/get-call.md)
* [통화 종료](https://docs.telloai.io/developer/rest/end-call.md)
* [통화 전환](https://docs.telloai.io/developer/rest/transfer-call.md)
* [대상 목록](https://docs.telloai.io/developer/rest/targets.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.