개발자/시작하기

공통 규칙

7개 엔드포인트에 모두 적용되는 규칙입니다.

관련 문서: 인증 · 상품과 주문 · README

#요청

  • 기본 URL: https://b2b.cardv.net/api/v1(Live), https://sandbox.cardv.net/api/v1(Sandbox)
  • 경로 끝에 슬래시를 붙이지 않습니다. /api/v1/orders/가 아니라 /api/v1/orders를 쓰세요.
  • JSON 본문은 UTF-8로 보내고 Content-Type: application/json을 지정합니다.
  • 금액은 "9.2500"처럼 문자열로 보냅니다. 반올림 오차를 막기 위해서입니다.
  • AcmeShop-CardV/1.4처럼 알아보기 쉬운 User-Agent를 지정하세요.

#금액과 시간

  • 금액은 소수점 넷째 자리까지 있는 문자열입니다. 예: "merchant_price": "9.2500"
  • 금액은 decimal 타입으로 읽으세요. 부동소수점(float)은 쓰면 안 됩니다.
  • 결제는 지갑 통화로 이뤄집니다(GET/account의 default_currency, 현재는 USD).
  • face_currency는 카드에 표시된 통화로, 지갑 통화와 다를 수 있습니다.
  • 원가 계산에는 항상 merchant_price를 쓰세요. price_label 같은 값은 화면 표시용입니다.
  • 모든 시각은 UTC 기준 ISO 8601 형식입니다. 예: 2026-09-29T08:15:30.123456Z
  • 초 단위 소수 자릿수는 달라질 수 있으니, 제대로 된 ISO 8601 파서를 쓰세요.
  • 서명에 쓰는 X-Timestamp는 Unix 시간(초)입니다.

#ID

구분예시설명
Merchant IDM00000001바뀌지 않습니다.
SKU IDS000456가격 조회와 주문에 씁니다.
상품 IDP000123SKU가 속한 상품입니다.
CardV 주문 IDO-00001234주문을 조회할 때 씁니다.
자체 주문번호SHOP-10001external_order_id. 1~120자이며 중복될 수 없습니다.
  • ID는 문자열로 저장하고, 형식을 해석하지 마세요. 길이가 늘어날 수 있습니다.
  • 주문에는 숫자형 id도 있지만 쓰지 마세요. order_id를 쓰세요.
  • 자체 주문번호에는 A–Z a–z 0–9 - _ .만 쓰세요.

#페이지 나누기

페이지 단위로 나눠 받는 엔드포인트는 GET/skus뿐입니다. limit과 offset을 보냅니다.

HTTP
GET /api/v1/skus?limit=100&offset=200
JSON
{"count": 1234, "limit": 100, "results": ["..."], "filter_options": {}}
  • limit 기본값은 100, 최대값은 500입니다. 500보다 크면 500으로 처리됩니다.
  • count는 조건에 맞는 전체 개수입니다. offset이 count에 도달할 때까지 계속 요청하세요.
  • limit이나 offset이 음수이거나 숫자가 아니면 HTTP 400이 반환됩니다.
  • 존재하지 않는 필터 값을 보내면 오류 대신 빈 목록이 반환됩니다.

#요청 한도

  • 기본 한도는 계정 전체 기준 분당 60회입니다. 모든 API 키와 포털 사용자가 이 한도를 함께 씁니다. 등급에 따라 한도가 다를 수 있습니다.

  • 1분은 시계의 :00초부터 계산합니다. 거절된 요청도 횟수에 포함됩니다.

  • 한도를 넘으면 HTTP 429와 함께 Retry-After 헤더(기다려야 할 초)가 반환됩니다.

    JSON
    {"detail": "Merchant API rate limit exceeded. Expected available in 23 seconds."}
  • 한도를 넘지 않으려면 SKU 목록을 캐시하고, 짧은 간격의 폴링 대신 Webhook을 쓰고, 429를 받을 때마다 조금 더 길게 기다리세요.

#오류

먼저 HTTP 상태 코드를 확인한 다음 JSON 본문을 읽으세요. 무엇이 잘못됐는지는 본문의 키로 판단합니다. 메시지 문구에 의존하지 마세요.

인증, 권한, 조회 실패(not found), 요청 한도 오류는 detail 키를 씁니다.

JSON
{"detail": "Order not found."}

주문과 가격 조회 오류는 문제가 된 필드 이름을 키로 씁니다.

JSON
{"balance": "Insufficient available balance."}

주문 항목의 형식이 잘못되면 항목별로 알려 줍니다. 순서는 보낸 items와 같습니다.

JSON
{"items": [{}, {"quantity": ["Ensure this value is greater than or equal to 1."]}]}
키발생 위치해결 방법
detail전체아래 상태 코드 표를 참고하세요.
itemsPOST/orders해당 항목을 고치세요. 가격이 바뀌었다면 다시 조회하세요.
balancePOST/orders포털에서 지갑을 충전하세요.
riskPOST/orders주문 한도에 걸렸습니다. CardV에 문의하세요.
external_order_idPOST/orders주문번호가 없거나, 너무 길거나, 다른 주문에 이미 쓰였습니다.
walletPOST/orders사용 가능한 지갑이 없습니다. CardV에 문의하세요.
quantity, amount가격 조회허용 범위를 벗어났거나 숫자가 아닙니다.
limit, offsetGET/skus올바른 숫자가 아닙니다.

JSON이 아닌 오류도 일부 있습니다.

  • error code: 1010 같은 일반 텍스트와 함께 오는 HTTP 403은 CardV 앞단의 네트워크 서비스에서 막힌 것입니다. 요청이 CardV까지 도달하지 않았습니다. 서버 IP와 User-Agent를 CardV에 알려 주세요.
  • 존재하지 않는 경로(404)나 프록시 오류(5xx)는 HTML을 반환할 수 있습니다.

오류를 로그로 남길 때 API 키, 서명, 코드는 절대 기록하지 마세요.

#HTTP 상태 코드

상태의미재시도
200성공. POST/orders에서는 이미 있는 주문이라는 뜻입니다.필요 없음
201새 주문이 생성됐습니다.필요 없음
400요청이 거절됐습니다. 결제되지 않았습니다.수정 후
403인증 정보, 서명, IP 문제 또는 포털 전용 엔드포인트입니다.수정 후
404찾을 수 없거나 귀사 계정에 공개되지 않았습니다.안 함
405이 경로에 맞지 않는 메서드입니다.안 함
429요청이 너무 많습니다.Retry-After 후
5xx 또는 타임아웃서버나 네트워크 문제입니다. 주문은 생성됐을 수 있습니다.예, 아래 참고

POST/orders를 재시도할 때는 반드시 같은 본문과 같은 주문번호를 쓰세요. 안전한 재시도 절차를 참고하세요.

#응답

  • brand_logo_url과 image_url은 CardV가 호스팅하는 이미지의 전체 URL이거나 ""입니다. 공개 이미지이므로 캐시해도 됩니다.
  • 주문의 invoice_url과 delivery_file_url은 /orders/O-00001234/invoice 같은 경로이며, 아직 없으면 ""입니다. 포털 전용이므로 API 키로 호출하면 HTTP 403이 반환됩니다. 인보이스와 코드 CSV 파일은 포털에서 확인하세요.

#호환성

  • 모르는 필드는 무시하세요. CardV는 API 버전을 바꾸지 않고 필드를 추가합니다.
  • 새 상태 값이 생길 수 있습니다. 모르는 상태는 "아직 완료되지 않음"으로 처리하세요.
  • JSON 키의 순서나 메시지 문구에 의존하지 마세요.

연동 관련 문의는 Merchant ID와 주문 ID 또는 요청 ID를 포함해 [email protected]로 보내 주세요.