개발자2026-11프리뷰

NinjaBuy Business API

Taobao, Weidian, 1688에서 상품을 가져오고, 가격과 재고를 동기화하고, 중국 판매자부터 창고 검수를 거쳐 고객 문 앞까지 모든 주문을 추적하세요. HTTPS 기반 JSON, 계정 하나, 잔액 하나.

기본 URL

이 사이트의 모든 경로는 하나의 기본 URL 아래에 있어요. Shopify 앱도, 내가 만드는 것도 같은 경로를 호출하므로 앱이 하는 일은 내 코드도 할 수 있어요.

https://www.ninjabuy.com/api/v1

AI 어시스턴트에게 묻고 싶나요? 같은 계정이 MCP https://www.ninjabuy.com/mcp에서도 작동해요: AI 어시스턴트(MCP).

카탈로그
  • 가져오기링크를 넣으면 판매에 드는 전체 비용이 나와요.
  • 상품판매하는 것과 등록된 곳.
  • 옵션각 옵션. 판매자의 SKU에 연결돼요.
  • 재고 수준지금 판매할 수 있는 것.
  • 동기화 규칙판매자가 가격을 바꿀 때 일어나는 일.
주문
계정
첫 호출
curl "https://www.ninjabuy.com/api/v1/balance" \
  -H "Authorization: Bearer $NINJABUY_API_KEY" \
  -H "NinjaBuy-Version: 2026-11"

인증

모든 요청에 API 키를 bearer 토큰으로 보내세요. 키는 nb_로 시작해요. 프리뷰 기간에는 저희 팀이 발급해요. Business 계정 설정이 끝나면 요청한 범위로, 원하는 채널을 통해 각 키를 한 번만 보내 드려요. 폐기를 요청하면 다음 요청부터 작동하지 않아요.

키는 서버에 보관하세요. 브라우저, 앱, 공개 저장소에 있는 키는 누구나 읽을 수 있고 내 잔액을 쓸 수 있어요.

다른 NinjaBuy 셀러를 대신해 작동하는 앱은 OAuth 2.1을 사용해요: 동적 클라이언트 등록, PKCE(S256)를 사용한 인가 코드 흐름, 셀러 본인의 승인 화면. 액세스 토큰은 같은 헤더에 넣고 같은 경로에서 사용해요. 액세스 토큰은 1시간 유효하고, 리프레시 토큰으로 7일간 갱신해요. AI 어시스턴트도 같은 방식으로 연결돼요(MCP).

products:read범위
가져오기, 상품, 옵션, 동기화 규칙 읽기.
products:write범위
상품 가져오기, 수정, 보내기, 삭제. 동기화 규칙 변경.
inventory:read범위
재고 수준 읽기.
orders:read범위
주문, 풀필먼트 주문, 배송 읽기.
orders:write범위
주문 생성, 보류, 해제, 취소. 잔액을 사용해요.
balance:read범위
잔액과 거래 내역 읽기.
webhooks:write범위
웹훅 엔드포인트를 관리해요.

키의 범위를 벗어난 호출은 403 insufficient-scope를 반환하고 필요한 범위를 알려 줘요.

헤더
Authorization: Bearer nb_7Qk2...vX9e
Response 401
HTTP/2 401

{
  "type": "https://www.ninjabuy.com/api/v1/problems/unauthorized",
  "title": "Unauthorized",
  "status": 401,
  "detail": "The API key is missing, wrong, expired or revoked.",
  "request_id": "req_7Hq2Lw9c"
}

버전 관리

경로에는 메이저 버전 /v1이 들어가요. 그 안에서는 날짜가 붙은 버전이 필드와 동작을 바꿔요. 개발에 쓴 버전은 NinjaBuy-Version 헤더로 고정하세요. 모든 응답은 같은 헤더에 사용한 버전을 표시해요.

2026-11이 현재 버전이며 프리뷰예요. 안정 버전으로 표시되기 전까지 이름과 필드가 바뀔 수 있어요. 모든 변경 사항은 변경 내역에 있으며, 호환성을 깨는 변경 전에는 모든 키 보유자에게 이메일로 알려 드려요.

한 버전 안에서는 추가만 해요: 새 경로, 새 선택 매개변수, 응답의 새 필드, 새 이벤트 유형. 모르는 필드는 무시하도록 클라이언트를 만드세요.

버전 고정
GET /api/v1/orders
NinjaBuy-Version: 2026-11

HTTP/2 200
NinjaBuy-Version: 2026-11

요청과 응답

  • JSON은 Content-Type: application/json으로 보내세요. 응답은 UTF-8 JSON이에요. 오류는 application/problem+json이에요.
  • 금액은 10진수 문자열과 통화로 된 객체예요: { "amount": "264.20", "currency": "CNY" }. NinjaBuy의 청구는 CN¥이고, 내 판매 가격은 스토어 통화예요.
  • ID는 종류를 나타내는 접두사가 붙은 문자열이에요(prd_, ord_, shp_). 내부 구조에 의존하지 마세요.
  • 시각은 UTC 기준 ISO 8601이에요. 국가는 두 글자 ISO 코드예요.
  • 모든 응답에는 X-Request-Id 헤더가 있고, 모든 오류에는 같은 ID가 request_id로 들어 있어요. 문의할 때 알려 주세요.
금액, ID, 날짜
{
  "id": "ord_3n7q",
  "created_at": "2026-11-01T09:14:02Z",
  "total": { "amount": "264.20", "currency": "CNY" },
  "suggested_price": { "amount": "49.99", "currency": "USD" }
}

페이지네이션

목록은 최신순으로 data, has_more, cursor로 반환돼요. has_more가 true인 동안 그 커서를 다시 보내 다음 페이지를 받으세요. 커서는 받을 때와 같은 필터에서만 작동해요.

limitinteger
1~100. 생략하면 25.
cursorstring
이전 페이지의 커서. 첫 페이지에서는 생략하세요.
curl "https://www.ninjabuy.com/api/v1/orders?limit=25&cursor=c_2v9kq" \
  -H "Authorization: Bearer $NINJABUY_API_KEY" \
  -H "NinjaBuy-Version: 2026-11"
Response 200
HTTP/2 200 OK

{
  "data": [
    { "id": "ord_3n7q", "status": "checked" },
    { "id": "ord_3n6z", "status": "shipped" }
  ],
  "has_more": true,
  "cursor": "c_1q4ea"
}

요청 한도

한도는 계정 단위이며 모든 키, OAuth 토큰, MCP 연결이 공유해요. 모든 응답은 IETF RateLimit-Policy와 RateLimit 헤더로 현재 상태를 알려 줘요. 거절은 429 rate-limited이며 Retry-After에 초 단위로 표시돼요.

시간 범위해당하는 것
"create-links";q=30;w=60마켓플레이스에서 상품을 읽는 호출: 가져오기 생성·새로 고침, 상품 보내기. 분당 30회이며 링크 API, MCP와 공유해요.
"default";q=120;w=60그 밖의 모든 호출. 분당 120회.
응답 429
HTTP/2 429
Content-Type: application/problem+json
Retry-After: 12
RateLimit-Policy: "create-links";q=30;w=60
RateLimit: "create-links";r=0;t=12

{
  "type": "https://www.ninjabuy.com/api/v1/problems/rate-limited",
  "title": "Too many requests",
  "status": 429,
  "detail": "Try again in 12 seconds.",
  "request_id": "req_7Hq2Lw9c"
}

멱등성

모든 POST에 Idempotency-Key(출력 가능한 ASCII 1~255자, UUID가 가장 좋아요)를 보내면 타임아웃 후 재시도로 두 번째 주문이 생기지 않아요. 24시간 동안 같은 경로, 같은 본문의 같은 키에는 첫 응답을 바이트 단위로 똑같이 Idempotent-Replayed: true와 함께 반환하며, 다시 실행하지도 한도에 포함하지도 않아요.

  • 같은 키에 다른 본문이나 경로: 422 idempotency-key-reused.
  • 첫 요청이 아직 실행 중: 409 idempotency-key-in-progress, Retry-After 포함.
  • 요청 한도 초과 거절은 응답이 아니에요. 키는 사용되지 않은 상태로 남으므로 Retry-After 이후 다시 시도하면 요청이 실행돼요.

주문에는 내 external_id도 붙어요. 같은 ID의 두 번째 주문은 어떤 키로 보내든 409 duplicate-order로 거절돼요.

재시도된 요청
POST /api/v1/orders
Idempotency-Key: 4f0c2b4e-9d1a-4e0f-b0a8-5d1d3c7e2f61

HTTP/2 201
Idempotent-Replayed: true
X-Request-Id: req_7Hq2Lw9c

오류

오류는 problem JSON(RFC 9457)이에요: type은 분기에 쓸 수 있는 고정 URL, title은 이름, detail은 이 경우를 보여 줄 수 있는 말로 설명하며, request_id로 저희 로그에서 찾을 수 있어요. 유효성 검사에 실패한 본문에는 errors가 추가되고, 각각 필드를 가리키는 JSON pointer가 있어요.

상태유형시점
400bad-json본문이 JSON이 아니에요.
400bad-body필드가 없거나 잘못되었어요. errors[]가 해당 위치를 가리켜요.
400bad-idempotency-keyIdempotency-Key가 비어 있거나, 너무 길거나, 출력 가능한 ASCII가 아니에요.
401unauthorized키나 토큰이 없거나, 잘못되었거나, 만료되었거나, 폐기되었어요.
403insufficient-scope키에 경로가 요구하는 범위가 없어요.
404not-found이 계정에 해당 객체가 없어요. 다른 계정의 ID도 같은 응답이에요.
405method-not-allowed경로는 있지만 이 메서드로는 안 돼요. Allow에 받는 메서드가 나와 있어요.
409duplicate-order이 external_id의 주문이 있어요. order가 해당 주문을 가리켜요.
409idempotency-key-in-progress이 키의 첫 요청이 아직 실행 중이에요.
409invalid-state객체가 지금은 그 작업을 할 수 없어요. 예: 배송된 주문 취소.
415unsupported-media-type본문이 application/json이 아니에요.
422idempotency-key-reused키가 다른 요청에 사용되었어요.
422unprocessable유효한 JSON이지만 처리할 수 없어요: 읽지 못한 링크, 품절된 옵션 등. detail에 무엇인지 나와요.
429rate-limited시간 범위 안에 호출이 너무 많아요. Retry-After 초만큼 기다리세요.
500internal-error저희 쪽 문제예요. 같은 Idempotency-Key로 다시 시도하세요.
503service-unavailable지금은 키를 확인하거나 스토어에 연결할 수 없어요. Retry-After 이후 다시 시도하세요.
Response 400
HTTP/2 400

{
  "type": "https://www.ninjabuy.com/api/v1/problems/bad-body",
  "title": "Invalid request body",
  "status": 400,
  "detail": "1 field is invalid.",
  "request_id": "req_7Hq2Lw9c",
  "errors": [
    {
      "pointer": "/ship_to/country",
      "detail": "Must be a two-letter country code."
    }
  ]
}