> For the complete documentation index, see [llms.txt](https://sharelink-docs.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://sharelink-docs.toss.im/guide/open-api/convention.md).

# 공통 규약

모든 API 호출에 공통으로 적용되는 규칙입니다. 인증·환경 설정은 [연동 시작하기](/guide/open-api/auth.md)를 먼저 보세요.

***

## 공통 응답 형식

모든 API는 아래 형태로 응답합니다.

**성공**

```json
{
  "resultType": "SUCCESS",
  "success": {
    // 각 API별 응답 본문
  }
}
```

**실패**

```json
{
  "resultType": "FAIL",
  "error": {
    "errorType": 400,
    "errorCode": "INVALID_ARGUMENT",
    "reason": "오류 내용"
  }
}
```

> **성공·실패는 반드시 `resultType` 으로 판별해 주세요.** HTTP 상태 코드만으로 분기하지 마시기 바랍니다. 요청 값 오류나 사용 한도 초과처럼 서버가 정상 처리한 실패는 HTTP 200으로 내려가고, 실패라는 사실은 `resultType: "FAIL"` 과 `error.errorCode` 에 담깁니다.

실제 데이터는 `success` 안에서 읽으시면 됩니다.

**응답 스키마는 하위호환으로 확장될 수 있습니다(필드 추가).** 모르는 필드는 무시하도록 구현해 주세요. 필드가 늘었다고 파싱이 깨지지 않아야 합니다.

### 오류 코드

**실패 원인은 `error.errorCode` 로 판별해 주세요.** `errorType` 은 일부 오류에만 채워지므로 분기 기준으로 삼지 마시기 바랍니다.

| `errorCode`                        | 의미                                                                                           | 조치                                           |
| ---------------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------- |
| `INVALID_ARGUMENT`                 | 파라미터 오류. 필수 값 누락·형식 오류와 **존재하지 않는 `categoryId`** 가 모두 여기에 해당합니다 (`errorType: 400` 이 함께 담깁니다) | 요청 형식을 고쳐 주세요. 재시도해도 결과가 같습니다                |
| `SHARELINK_OPENAPI_ACCESS_DENIED`  | 인증 정보가 유효하지 않거나, 등록되지 않은 출발지 IP에서 호출하셨습니다                                                    | 인증 정보 상태와 어드민에 등록하신 호출 서버 IP를 확인해 주세요        |
| `SHARELINK_OPENAPI_QUOTA_EXCEEDED` | 오늘 쓰실 수 있는 일 사용 상한을 모두 사용하셨습니다                                                               | 이 페이지의 **일 사용 상한** 을 참고해 주세요. 자정(KST)에 리셋됩니다 |
| `500`                              | 서버 오류                                                                                        | 잠시 후 재시도해 주세요                                |

액세스 토큰이 없거나 만료·무효인 경우(`UNAUTHORIZED`)와 호출 속도 제한을 넘긴 경우(`TOO_MANY_REQUEST`)는 요청이 서버에 닿기 전 API 게이트웨이에서 각각 HTTP 401·429로 응답됩니다.

`errorCode` 는 추가될 수 있습니다. 목록에 없는 값이 오더라도 동작이 멈추지 않도록, 알 수 없는 `errorCode` 는 재시도하지 않는 실패로 처리하시고 로그에 남겨 주시길 권장드립니다.

### 재시도

| 상황                                                                | 처리                                                           |
| ----------------------------------------------------------------- | ------------------------------------------------------------ |
| `500` · HTTP 429                                                  | 지수 백오프로 재시도해 주세요. 429는 `Retry-After` 헤더를 우선 따릅니다             |
| `SHARELINK_OPENAPI_QUOTA_EXCEEDED`                                | **재시도하지 마세요.** 자정(KST) 리셋 전까지는 결과가 같습니다                      |
| `INVALID_ARGUMENT` · `SHARELINK_OPENAPI_ACCESS_DENIED` · HTTP 401 | **재시도하지 마세요.** 요청이나 자격의 문제라 그대로 다시 보내도 결과가 같습니다. 원인을 고쳐야 합니다 |

조회 API(`GET`)는 멱등하므로 안전하게 재시도하실 수 있습니다.

***

## 호출 제한 (Rate Limit)

| 항목     | 기준                             |
| ------ | ------------------------------ |
| 지속 한도  | 파트너 단위 **10 rps** (전 엔드포인트 합산) |
| 순간 버스트 | 최대 30                          |
| 초과 시   | HTTP 429 + `Retry-After` 헤더    |

한도는 모든 엔드포인트를 합산해 파트너 단위로 적용됩니다.

**응답을 저장해서 재사용하시는 것을 전제로 설계해 주세요.** 상품 랭킹은 하루 한 번 갱신되므로 매번 새로 호출하실 필요가 없고, 발급받은 쉐어링크도 저장해 두고 재사용하시면 됩니다.

***

## 일 사용 상한

바로 위 호출 제한이 *순간* 호출 속도를 제한한다면, 일 사용 상한은 *하루에 가져가실 수 있는 총량*을 제한합니다. 적용 지점과 초과 시 응답이 서로 다르므로 두 값을 합쳐서 계산하지 않으셔도 됩니다.

| 항목        | 기준                                                         |
| --------- | ---------------------------------------------------------- |
| 조회로 받은 상품 | 하루 **10,000개**                                             |
| 새로 발급한 링크 | 하루 **10,000개**                                             |
| 적용 단위     | 발급받으신 인증 정보 1건                                             |
| 리셋        | 매일 자정(KST)                                                 |
| 초과 시      | HTTP 200 + `errorCode: "SHARELINK_OPENAPI_QUOTA_EXCEEDED"` |

두 한도는 **서로 독립적**입니다. 합산되지 않으며, 한쪽을 다 쓰셔도 다른 쪽은 그대로 사용하실 수 있습니다.

한도를 모두 쓰신 뒤의 응답입니다. 호출 속도 제한(HTTP 429)과 달리 **HTTP 200으로 내려가므로 `errorCode` 로 구분해 주세요.**

```json
{
  "resultType": "FAIL",
  "error": {
    "errorCode": "SHARELINK_OPENAPI_QUOTA_EXCEEDED",
    "reason": "오늘 사용할 수 있는 요청 한도를 모두 사용했어요."
  }
}
```

두 축 중 어느 쪽이 소진됐는지는 응답에 담기지 않습니다. 상품 조회와 링크 발급 중 어느 호출에서 받으셨는지로 판단해 주세요.

### 세는 방식

| 대상             | 세는 기준                                                        |
| -------------- | ------------------------------------------------------------ |
| 상품 목록·상세 조회    | 응답에 담겨 나간 상품 수를 그대로 누적합니다. 같은 상품을 다시 조회하시면 그때마다 다시 차감됩니다     |
| 쉐어링크 발급        | 새로 발급된 링크만 셉니다. 이미 발급받으신 상품을 다시 요청하시면 기존 링크가 반환되므로 차감되지 않습니다 |
| 연결성 확인·카테고리 조회 | 상품을 반환하지 않으므로 차감되지 않습니다                                      |

한도는 요청을 받기 전에 확인하므로 **응답이 도중에 잘리는 일은 없습니다.** 남은 한도가 있으면 그 요청은 그대로 처리됩니다.

### 한도에 닿지 않으시려면

* **응답을 저장해 재사용해 주세요.** 누적 방식이라 같은 목록을 하루에 여러 번 다시 받아오시면 한도가 그만큼 빨리 줄어듭니다. 위 호출 제한에서 안내드린 캐싱 설계가 그대로 적용됩니다.
* **발급받으신 쉐어링크를 저장해 두고 재사용해 주세요.** 같은 상품을 다시 요청하셔도 새 링크가 생기지 않으므로 한도를 쓰지 않습니다.

정상적인 연동에서는 한도에 닿지 않는 수준입니다. 상품을 매일 전량 다시 수집하셔야 하는 등 특별한 사정이 있으시면 연동 담당자에게 문의해 주세요.

***

## 커서 페이징

상품 목록 API 3종(카테고리 베스트·베스트·하루특가)은 커서 방식으로 페이징합니다.

| 파라미터     | 설명                           |
| -------- | ---------------------------- |
| `cursor` | 다음 페이지 조회 위치. 첫 요청에는 넣지 않습니다 |
| `size`   | 한 번에 받을 개수                   |

**응답**

| 필드           | 설명                                    |
| ------------ | ------------------------------------- |
| `nextCursor` | 다음 페이지 조회에 사용할 커서. 다음 페이지가 없으면 `null` |
| `hasNext`    | 다음 페이지 존재 여부                          |

**사용법**

1. 첫 요청은 `cursor` 없이 호출합니다.
2. 응답의 `hasNext`가 `true`이면, `nextCursor` 값을 그대로 `cursor`에 담아 다시 호출합니다.
3. `hasNext`가 `false`가 될 때까지 반복합니다.

> `cursor` 값은 내부 형식이 정해져 있지 않은 문자열입니다. **값을 해석하거나 직접 만들어 넣지 마시고**, 직전 응답이 준 값을 그대로 전달해 주세요.

`size`가 허용 범위를 벗어나면 오류 대신 허용 범위 안으로 자동 보정됩니다. 엔드포인트별 허용 범위는 각 문서를 확인해 주세요.

***

## 상품 카드 공통 필드

상품 목록 API 3종은 아래 필드를 공통으로 내려줍니다.

| 필드              | 타입      | 설명                                          |
| --------------- | ------- | ------------------------------------------- |
| `tacaItemId`    | number  | 상품 옵션 ID. **상세 조회·링크 발급에 사용하는 식별자입니다**      |
| `displayName`   | string  | 상품명                                         |
| `thumbnailUrl`  | string  | 썸네일 이미지 주소                                  |
| `productUrl`    | string  | 상품 페이지 주소. **추적이 없는 일반 링크입니다** (아래 주의사항 참고) |
| `displayPrice`  | number  | 판매가 (원)                                     |
| `originalPrice` | number  | 정가 (원)                                      |
| `discountRate`  | number  | 할인율 (%)                                     |
| `isSoldOut`     | boolean | 품절 여부                                       |
| `reviewScore`   | number  | 리뷰 평점                                       |
| `reviewCount`   | number  | 리뷰 수                                        |
| `rank`          | number  | 목록 내 순위. 1부터 시작하며 페이지 경계를 넘어 연속됩니다          |

***

## 공통 주의사항

### 게시글 링크는 반드시 발급 API로 만들어 주세요

조회 API 응답의 `productUrl`은 **추적이 되지 않는 일반 상품 링크**입니다. 이 링크로 발생한 구매는 수익으로 집계되지 않습니다.

게시글에 넣으실 링크는 [쉐어링크 발급 API](/guide/open-api/api/link.md)로 발급받은 `shortUrl` 또는 `originUrl`을 사용해 주세요.

### 개인화 정보는 제공되지 않습니다

서버 간 호출이라 특정 사용자 정보가 없습니다. 쿠폰·배송지·적립 등 사용자별로 달라지는 정보는 응답에 포함되지 않으며, 상품 자체 정보만 제공됩니다.

### 가격·품절 상태는 실시간으로 변합니다

응답을 저장해서 사용하시는 경우, 게시 시점의 가격·품절 상태가 실제와 달라질 수 있습니다. [상품 상세 조회](/guide/open-api/api/product-detail.md)로 최신 상태를 확인하실 수 있습니다.

### 성인 상품은 제공되지 않습니다

Open API 조회 기능은 성인 상품을 제공하지 않습니다.

***

## 버전·변경 정책

외부 경로는 `/openapi` 하위로 제공합니다.

* **필드 추가처럼 하위호환을 지키는 변경은 기존 경로에 그대로 반영**됩니다. 그래서 모르는 필드를 무시하도록 구현해 주시길 권장드립니다.
* **하위호환을 깨는 변경은 별도 경로로 제공**합니다 (예: `/openapi/v2`). 쓰시던 경로가 갑자기 달라지지 않습니다.
* 기존 기능을 걷어내는 경우 **사전에 공지**드립니다.

***

## 이용 조건

* 제공되는 데이터는 **제휴 목적 범위 내에서만** 사용해 주세요.
* 가격 크롤링, 무단 재판매, 비정상적 대량 수집 등은 이용이 제한되거나 차단될 수 있습니다.

자세한 약관과 정산 조건은 담당자에게 문의해 주세요.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://sharelink-docs.toss.im/guide/open-api/convention.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
