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

# 하위 계정: 최종 고객별 키, 한도, 사용량

> 고객마다 API 키, 크레딧 한도, 동시 실행 한도를 따로 주고, 결과를 분리하고, 고객별 사용량을 조회합니다. 청구서는 하나입니다.

querying.ai를 내 제품 안에서 쓴다면 고객마다 하위 계정을 하나씩 만드세요. 하위 계정은 자기 API 키,
한도, 태스크, 배치, 모니터를 가집니다. 크레딧은 내 잔액에서 나가고, 사용량 엔드포인트로 고객마다 얼마를
청구할지 알 수 있습니다.

## 하위 계정의 동작

* **자기 키와 자기 결과.** 하위 계정 키는 다른 키처럼 태스크, 배치, 모니터를 제출하고 조회하며,
  자기 작업만 봅니다. Acme 키로 만든 태스크는 Globex 키와 내 키에 `404`를 돌려줍니다.
* **내 크레딧.** 하위 계정의 태스크는 내 잔액에서 차감됩니다. 하위 계정에는 잔액이 없으므로
  하위 계정 키로 `GET /v1/credits`나 `GET /v1/usage`를 호출하면 `403 SUB_ACCOUNT_FORBIDDEN`이 반환됩니다.
* **내 처리 용량.** 플랜이나 계약의 동시 실행 한도는 내 태스크와 모든 하위 계정을 합쳐 적용되므로,
  하위 계정을 만들어도 용량은 늘지 않습니다. `GET /v1/async/status`는 이 공유 대기열을 내 키로 합쳐 보여 주고,
  하위 계정 키로 호출하면 `403 SUB_ACCOUNT_FORBIDDEN`이 반환됩니다.
* **내 모니터 한도.** `GET /v1/monitors/capabilities`의 `monitors` 한도는 내 모니터와 모든 하위 계정의
  모니터를 합쳐 세고, `prompts`와 `tasksPerRun` 한도도 하위 계정의 모니터에 내 모니터와 똑같이 적용됩니다.
* **자기 한도.** `monthlyCreditLimit`는 UTC 달력 기준 한 달에 청구될 수 있는 크레딧의 상한입니다.
  `concurrencyLimit`는 내 한도 안에서 그 하위 계정의 대기 중이거나 실행 중인 태스크 수 상한입니다. 둘 다
  선택입니다.
* **한 단계.** 하위 계정은 하위 계정을 가질 수 없습니다. 하위 계정 모니터의 알림 메일은 내 계정의
  관리자에게 갑니다.

## 하위 계정을 관리할 수 있는 키

`/v1/sub-accounts` 엔드포인트는 엔진 범위와 일일 크레딧 한도가 없는 내 API 키로 호출하세요. 다른 키는
`403 SUB_ACCOUNT_FORBIDDEN`을 받습니다. 그렇지 않으면 제한된 키가 자기 제한이 없는 키를 발급할 수 있기
때문입니다. 하위 계정 자신의 키도 같은 오류를 받습니다.

```json theme={"theme":"css-variables"}
{
  "success": false,
  "error": {
    "code": "SUB_ACCOUNT_FORBIDDEN",
    "message": "Managing sub-accounts needs an API key without an engine scope or a daily credit limit",
    "timestamp": "2026-10-19T09:00:00.000Z"
  }
}
```

## 하위 계정과 키 만들기

```bash theme={"theme":"css-variables"}
curl -X POST https://api.querying.ai/v1/sub-accounts \
  -H "Authorization: Bearer $QUERYING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme", "externalId": "cust_acme", "monthlyCreditLimit": 200000, "concurrencyLimit": 50}'
```

응답은 `201`입니다.

```json theme={"theme":"css-variables"}
{
  "success": true,
  "data": {
    "id": "0199d2a4-5b10-7000-8000-000000000001",
    "name": "Acme",
    "externalId": "cust_acme",
    "status": "active",
    "monthlyCreditLimit": 200000,
    "concurrencyLimit": 50,
    "createdAt": "2026-10-09T09:00:00.000Z",
    "suspendedAt": null,
    "usage": { "month": "2026-10", "credits": 0, "tasks": 0, "reservedCredits": 0 }
  }
}
```

| 필드 | 필수 | 설명 |
| - | - | - |
| `name` | 예 | 1–128자. |
| `externalId` | 아니요 | 이 고객에 대한 내 쪽 id. 1–128자이고 내 하위 계정 사이에서 고유합니다. 같은 값으로 다시 만들면 `409 SUB_ACCOUNT_EXISTS`를 돌려주므로 재시도해도 중복이 생기지 않습니다. 기존 하위 계정은 `GET /v1/sub-accounts?externalId=cust_acme`로 찾습니다. |
| `monthlyCreditLimit` | 아니요 | 0.01–20,000,000크레딧, 소수점 두 자리까지. 빼거나 `null`을 보내면 상한이 없습니다. |
| `concurrencyLimit` | 아니요 | 정수 1–100,000. 빼거나 `null`을 보내면 상한이 없습니다. |

그 밖의 필드는 `400 VALIDATION_ERROR`를 돌려주므로, 한도 이름을 잘못 써서 고객이 무제한으로 남는 일이
없습니다.

그다음 하위 계정에 키를 발급합니다.

```bash theme={"theme":"css-variables"}
curl -X POST https://api.querying.ai/v1/sub-accounts/$SUB_ACCOUNT_ID/keys \
  -H "Authorization: Bearer $QUERYING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "production", "allowedTaskTypes": ["CHATGPT", "GEMINI"]}'
```

```json theme={"theme":"css-variables"}
{
  "success": true,
  "data": {
    "id": "b7e4c1a2-...",
    "name": "production",
    "keyPrefix": "vt_3f9a1c2b",
    "createdAt": "2026-10-09T09:01:00.000Z",
    "allowedTaskTypes": ["CHATGPT", "GEMINI"],
    "dailyCreditLimit": null,
    "expiresAt": null,
    "key": "vt_3f9a1c2b..."
  }
}
```

> [!WARNING]
>
> `key`는 이 응답에만 나옵니다. 지금 저장하세요. 다시는 보여 주지 않습니다.

키 설정은 대시보드 키와 같으며 모두 선택입니다: `name`(1–64자, 기본 `default`), `allowedTaskTypes`,
`dailyCreditLimit`, `expiresAt`(5분 후부터 2년 후까지). 제한 없는 키는 본문 없이 보내세요.

하위 계정마다 활성 키는 최대 5개이며, 폐기되거나 만료된 키는 세지 않습니다. 6번째 키는
`409 KEY_LIMIT`을 반환하므로 먼저 하나를 폐기하세요.

고객의 키는 다른 키와 똑같이 모든 엔드포인트에서 쓰입니다.

```bash theme={"theme":"css-variables"}
curl -X POST https://api.querying.ai/v1/async/task \
  -H "Authorization: Bearer $ACME_KEY" \
  -H "Content-Type: application/json" \
  -d '{"taskType": "CHATGPT", "payload": {"prompt": "best project management software", "country": "US"}}'
```

## 키 관리

`GET /v1/sub-accounts/{id}/keys`는 하위 계정이 가졌던 모든 키를 폐기·만료된 키까지 포함해 최신순으로
나열합니다. 활성 키는 `revokedAt`과 `expiresAt`으로 가려내세요.

```json theme={"theme":"css-variables"}
{
  "success": true,
  "data": {
    "keys": [
      {
        "id": "b7e4c1a2-...",
        "name": "production",
        "keyPrefix": "vt_3f9a1c2b",
        "createdAt": "2026-10-09T09:01:00.000Z",
        "revokedAt": null,
        "lastUsedAt": "2026-10-19T08:58:12.000Z",
        "allowedTaskTypes": ["CHATGPT", "GEMINI"],
        "dailyCreditLimit": null,
        "expiresAt": null
      },
      {
        "id": "4d2a9e10-...",
        "name": "staging",
        "keyPrefix": "vt_8c01d5e7",
        "createdAt": "2026-10-01T12:00:00.000Z",
        "revokedAt": "2026-10-09T09:02:00.000Z",
        "lastUsedAt": "2026-10-08T17:40:03.000Z",
        "allowedTaskTypes": [],
        "dailyCreditLimit": null,
        "expiresAt": null
      }
    ]
  }
}
```

`DELETE /v1/sub-accounts/{id}/keys/{keyId}`는 키를 폐기하고
`{"success": true, "data": {"revoked": "<keyId>"}}`를 돌려줍니다. 이미 폐기됐거나 그 하위 계정의 키가
아니면 `404 NOT_FOUND`를 반환합니다.

## 한도

| 한도 | 세는 대상 | 넘었을 때 |
| - | - | - |
| `monthlyCreditLimit` | 이번 UTC 달에 그 하위 계정에 청구된 크레딧과 아직 실행 중인 태스크가 잡아 둔 크레딧 | `429 SUB_ACCOUNT_CREDIT_LIMIT` |
| `concurrencyLimit` | 그 하위 계정의 대기 중이거나 실행 중인 태스크 | `429 PLAN_CONCURRENCY_LIMIT`, `details.source: "sub_account"` |
| 내 플랜이나 계약 한도 | 내 태스크와 모든 하위 계정의 태스크 | `429 PLAN_CONCURRENCY_LIMIT`, `details.source: "plan"` 또는 `"contract"` |
| 내 잔액 | 전체 | `402 INSUFFICIENT_CREDITS` |

자기 한도에 걸린 하위 계정만 거절되고 다른 고객은 계속 처리됩니다. 한도를 올리면 다음 요청부터
적용됩니다.

```json theme={"theme":"css-variables"}
{
  "success": false,
  "error": {
    "code": "SUB_ACCOUNT_CREDIT_LIMIT",
    "message": "Sub-account monthly credit limit 200000 would be exceeded (199998 used, 3 needed)",
    "details": { "limit": 200000, "used": 199998, "needed": 3, "retryAfterSec": 1814400 },
    "timestamp": "2026-10-09T09:00:00.000Z"
  }
}
```

`retryAfterSec`는 월간 집계가 다시 시작되는 다음 UTC 달의 시작까지 남은 초입니다. 계정 전체 한도는
[크레딧과 한도](/ko/concepts/credits-and-limits.md)를 참고하세요.

## 하위 계정 현재 상태 확인

`GET /v1/sub-accounts/{id}`는 하위 계정을 이번 달 사용량, 그리고 지금 대기 중이거나 실행 중인 태스크
수 `activeTasks`와 함께 돌려줍니다. `concurrencyLimit`와 비교하면 고객이 상한에 얼마나 가까운지 알 수
있습니다.

```json theme={"theme":"css-variables"}
{
  "success": true,
  "data": {
    "id": "0199d2a4-5b10-7000-8000-000000000001",
    "name": "Acme",
    "externalId": "cust_acme",
    "status": "active",
    "monthlyCreditLimit": 200000,
    "concurrencyLimit": 50,
    "createdAt": "2026-10-09T09:00:00.000Z",
    "suspendedAt": null,
    "usage": { "month": "2026-10", "credits": 48211.5, "tasks": 39870, "reservedCredits": 37.5 },
    "activeTasks": 31
  }
}
```

위 값은 예시입니다. `usage`의 `credits`와 `tasks`는 이번 UTC 달에 청구된 양이고, `reservedCredits`는
아직 실행 중인 태스크가 잡아 둔 크레딧입니다.

## 사용량과 청구

모든 청구는 내 결제 원장에도 그대로 나옵니다. 아래 엔드포인트는 그 청구를 고객별로 나눠 보여 줍니다.
실패한 태스크는 청구되지 않고 집계에도 들어가지 않습니다. 크레딧 값은 소수점 두 자리까지 있습니다.

* `GET /v1/sub-accounts`는 하위 계정을 오래된 순으로 나열하고, 각 항목에 이번 달 `usage`를 붙입니다.
  `limit`(기본 100, 최대 1,000)로 페이지를 나누고 `nextCursor`를 `cursor`로 다시 보내세요.
* `GET /v1/sub-accounts/usage`는 UTC 날짜 범위의 하위 계정별 합계를 줍니다.
* `GET /v1/sub-accounts/{id}/usage`는 하위 계정 하나의 일별, 엔진별 청구를 줍니다.

두 사용량 엔드포인트 모두 `from`과 `to`를 `YYYY-MM-DD`로 받으며 양 끝을 포함합니다. `from`의 기본값은
이번 UTC 달 1일, `to`는 오늘이고, 범위는 최대 366일입니다.

### 전체 하위 계정

```bash theme={"theme":"css-variables"}
curl "https://api.querying.ai/v1/sub-accounts/usage?from=2026-10-01&to=2026-10-31" \
  -H "Authorization: Bearer $QUERYING_API_KEY"
```

예시:

```json theme={"theme":"css-variables"}
{
  "success": true,
  "data": {
    "from": "2026-10-01",
    "to": "2026-10-31",
    "credits": 184200,
    "tasks": 61400,
    "subAccounts": [
      { "id": "0199d2a4-5b10-7000-8000-000000000001", "name": "Acme", "externalId": "cust_acme", "credits": 150000, "tasks": 50000 },
      { "id": "0199d2a4-6c20-7000-8000-000000000002", "name": "Globex", "externalId": "cust_globex", "credits": 34200, "tasks": 11400 }
    ]
  }
}
```

하위 계정은 큰 순서로 나옵니다. 범위 안에 청구가 없는 하위 계정은 빠집니다.

### 하위 계정 하나

```bash theme={"theme":"css-variables"}
curl "https://api.querying.ai/v1/sub-accounts/$SUB_ACCOUNT_ID/usage?from=2026-10-08&to=2026-10-09" \
  -H "Authorization: Bearer $QUERYING_API_KEY"
```

예시:

```json theme={"theme":"css-variables"}
{
  "success": true,
  "data": {
    "id": "0199d2a4-5b10-7000-8000-000000000001",
    "from": "2026-10-08",
    "to": "2026-10-09",
    "credits": 3062.5,
    "tasks": 2950,
    "days": [
      { "date": "2026-10-08", "taskType": "CHATGPT", "credits": 1500, "tasks": 1500 },
      { "date": "2026-10-08", "taskType": "GEMINI", "credits": 312.5, "tasks": 250 },
      { "date": "2026-10-08", "taskType": "OTHER", "credits": 50, "tasks": 0 },
      { "date": "2026-10-09", "taskType": "CHATGPT", "credits": 1200, "tasks": 1200 }
    ]
  }
}
```

* 최상위 `credits`와 `tasks`는 `days`의 합계입니다.
* `days`는 청구가 있었던 UTC 날짜와 엔진마다 한 행이며, 날짜순, 그다음 `taskType`순입니다. 청구가 없는
  날은 행이 없습니다.
* `taskType: "OTHER"`는 태스크가 아닌 청구입니다. 예를 들어 모니터의
  [경쟁사 분석](/ko/monitors.md#비용과-일정)입니다. 크레딧은 더하지만 `tasks`는 늘리지 않습니다.

## 정지와 재개

```bash theme={"theme":"css-variables"}
curl -X PATCH https://api.querying.ai/v1/sub-accounts/$SUB_ACCOUNT_ID \
  -H "Authorization: Bearer $QUERYING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "suspended"}'
```

* 그 키들은 5초 안에 `401`을 돌려줍니다.
* 모니터 실행이 멈추고, 아직 시작하지 않은 배치 항목은 `API_KEY_INACTIVE`로 끝납니다.
* 이미 대기 중이거나 실행 중인 태스크는 끝까지 처리되고 청구됩니다.

`{"status": "active"}`를 보내면 키와 모니터가 돌아옵니다. 모니터는 놓친 실행을 몰아서 하지 않고 돌아올
때 한 번 실행합니다. 같은 `PATCH`로 `name`, `externalId`, `monthlyCreditLimit`, `concurrencyLimit`도
바꿉니다. `null`은 한도나 `externalId`를 없앱니다. 하위 계정은 삭제할 수 없으니 정지하세요.

## 오류

| 상태 | 코드 | 원인 |
| - | - | - |
| `400` | `VALIDATION_ERROR` | JSON이 올바르지 않거나, 모르는 필드가 있거나, 값이 범위를 벗어났거나, 사용량 범위가 잘못됐습니다. |
| `403` | `SUB_ACCOUNT_FORBIDDEN` | 키에 엔진 범위나 일일 크레딧 한도가 있거나, 하위 계정의 키입니다. |
| `404` | `NOT_FOUND` | 내 하위 계정 중 그 id가 없거나, 그 id의 활성 키가 없습니다. |
| `409` | `SUB_ACCOUNT_EXISTS` | 다른 하위 계정이 이미 그 `externalId`를 쓰고 있습니다. |
| `409` | `KEY_LIMIT` | 하위 계정에 이미 활성 키가 5개 있습니다. |

## 엔드포인트

| 메서드와 경로 | 용도 |
| - | - |
| [`POST /v1/sub-accounts`](/ko/api-reference/sub-accounts/create-sub-account) | 만들기 |
| [`GET /v1/sub-accounts`](/ko/api-reference/sub-accounts/list-sub-accounts) | 목록. `externalId`, `limit`, `cursor`를 받습니다 |
| [`GET /v1/sub-accounts/{id}`](/ko/api-reference/sub-accounts/get-sub-account) | 하위 계정 하나, `activeTasks` 포함 |
| [`PATCH /v1/sub-accounts/{id}`](/ko/api-reference/sub-accounts/update-sub-account) | 설정 변경, 정지, 재개 |
| [`GET /v1/sub-accounts/usage`](/ko/api-reference/sub-accounts/list-usage) | 하위 계정별 합계 |
| [`GET /v1/sub-accounts/{id}/usage`](/ko/api-reference/sub-accounts/get-usage) | 하위 계정 하나의 일별, 엔진별 사용량 |
| [`GET /v1/sub-accounts/{id}/keys`](/ko/api-reference/sub-accounts/list-keys) | 폐기·만료된 키를 포함한 키 목록 |
| [`POST /v1/sub-accounts/{id}/keys`](/ko/api-reference/sub-accounts/issue-key) | 키 발급 |
| [`DELETE /v1/sub-accounts/{id}/keys/{keyId}`](/ko/api-reference/sub-accounts/revoke-key) | 키 폐기 |


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