API 규약
목록 · 레이트리밋
커서 페이지네이션과 호출 한도(429), 응답 헤더 읽는 법.
커서 페이지네이션
목록 API 는 페이지 번호(offset) 대신 커서로 다음 페이지를 가져옵니다. 목록을 읽는 사이 새 결제가 들어와도 건너뛰거나 겹치는 항목이 생기지 않습니다.
| 쿼리 | 뜻 |
|---|---|
limit | 한 번에 받을 건수. 기본 20, 최대 100(100보다 크게 보내면 100건만 옵니다) |
cursor | 이전 응답의 page.next_cursor 를 그대로. 첫 페이지는 비웁니다. |
GET /api/v1/payments?limit=2
{
"data": [
{"id": 8812, "payment_no": "P-2026-1028-0007", "status": "APPROVED", "amount": 29900, "...": "..."},
{"id": 8809, "payment_no": "P-2026-1028-0004", "status": "FAILED", "amount": 15000, "...": "..."}
],
"page": {"next_cursor": "MTc5MzE0NTYwMC4xMjM0NTZ8ODgwOQ", "has_more": true}
}- 정렬은 최신 등록순으로 고정입니다. 정렬을 바꾸는 파라미터는 없습니다.
has_more가false면 마지막 페이지입니다. 이때next_cursor는null입니다.- 커서 값의 모양은 바뀔 수 있으니 해석하거나 직접 만들지 마세요. 형식이 깨진 커서는
400 INVALID_REQUEST입니다. - 다음 페이지를 읽을 때도 필터 쿼리는 같게 보냅니다. 쿼리스트링 전체가 서명에 들어갑니다.
Python — 끝까지 읽기
import time
from urllib.parse import urlencode
def all_payments(call, **filters):
"""call 은 '인증 · 요청 서명' 문서의 함수입니다. 최신 결제부터 끝까지 읽습니다."""
cursor = None
while True:
query = {"limit": 100, **filters}
if cursor:
query["cursor"] = cursor
res = call("GET", "/payments?" + urlencode(query)) # 서명도 이 주소(쿼리 포함)로 합니다
if res.status_code == 429:
wait = int(res.headers.get("Retry-After", "60"))
time.sleep(wait)
continue
res.raise_for_status()
body = res.json()
yield from body["data"]
if not body["page"]["has_more"]:
break
cursor = body["page"]["next_cursor"]목록별 필터
| 목록 | 필터 쿼리 |
|---|---|
GET /api/v1/customers | status · q(검색어) · external_ref(고객사 회원 ID, 정확히 일치) |
GET /api/v1/billing-keys | customer_id · active_only(기본 true) |
GET /api/v1/invoices | status · customer_id |
GET /api/v1/payments | status · customer_id · invoice_id |
GET /api/v1/subscriptions | status · customer_id |
GET /api/v1/register-windows | status(OPEN · USED · EXPIRED) · merchant_ref |
GET /api/v1/charge-consents | customer_id · status(ACTIVE · REVOKED) |
계약의 월별 청구 금액 목록(GET /api/v1/subscriptions/{id}/charges)은 회차 수가 정해져 있어 페이지네이션이 없습니다.
레이트리밋(호출 한도)
호출 한도는 가맹점별 분당 횟수입니다. 매 분 정각에 새로 셉니다.
- 기본 한도는 분당 60회입니다. 가맹점마다 다를 수 있으니 실제 값은 응답 헤더
X-RateLimit-Limit으로 확인하세요. - 결제·계약·등록창·수시결제 동의 경로(
/payments·/subscriptions·/register-windows·/charge-consents로 시작하는 경로, 조회 포함)는 결제사 처리량을 지키기 위해 따로 세는 낮은 한도를 씁니다 — 기본 한도의 4분의 1(최소 5회). 두 한도는 서로의 횟수를 쓰지 않습니다. - 빌링플러스가 직접 돌리는 매달 자동결제는 이 한도와 관계없습니다. API 호출이 많아도 정기결제가 밀리지 않습니다.
| 응답 헤더 | 뜻 |
|---|---|
X-RateLimit-Limit | 이 요청에 적용된 분당 한도 |
X-RateLimit-Remaining | 이번 분에 남은 횟수 |
X-RateLimit-Reset | 한도가 다시 채워지기까지 남은 초 |
Retry-After | 429 일 때만. 다시 보내도 되는 시간(초) — X-RateLimit-Reset 과 같은 값 |
429
{
"error": {
"code": "RATE_LIMITED",
"message": "요청이 너무 많습니다. 분당 15회까지 호출할 수 있습니다.",
"detail": {"limit": 15, "window_seconds": 60, "retry_after": 23},
"request_id": "req_0b1c2d3e4f5a6b7c8d9e0f1a"
}
}429 를 받은 POST 는 실행되지 않았습니다. Retry-After 초 뒤 같은 멱등키로 다시 보내면 됩니다(서명·nonce 는 새로). 여러 건을 한꺼번에 보낼 때는 X-RateLimit-Remaining 을 보고 속도를 조절하세요.
개발자센터