API 레퍼런스

청구서 API

청구 서버의 청구서 생성·조회·재발송·삭제·취소와 공개 청구서 조회 규격입니다.

BASE_URL: https://api.dev.caripay.co.kr · 인증 헤더 x-access-token: {accessToken} (공개 청구서 조회 제외)

응답 봉투는 { result_code, result_msg, result_data }이며 result_code: 0만 성공입니다. 요청·응답 규격

청구서 생성·발송

HTTP
POST /app/v1/sales/bill
필드필수형식설명
templateType–SAME(기본) / INDIVIDUAL동일 금액 / 수신인별 금액
requestId–^[A-Za-z0-9_-]{8,64}$멱등 키. 같은 값 재요청은 새 청구서를 만들지 않음. 수신자 1명일 때만
reason✅문자열청구 사유. 알림 본문에 표시(60자 이내 권장)
description–문자열안내 메시지(200자 이내 권장). 알림 본문에 표시
amount✅정수 ≥100청구 금액(원). SAME일 때
sendChannel–ALIMTALK(기본) / SMS / ALIMTALK_THEN_SMS발송 수단
webhookUrl–https://… ≤500자결제 완료·취소 시 POST 할 파트너 웹훅. 규격
webhookSecret–^[\x21-\x7E]{16,128}$웹훅 서명 비밀. 있으면 전송마다 X-CariPay-Signature. webhookUrl과 함께
members[]✅배열 ≥1수신자. studentName(이름), studentPhone(^\d{10,11}$), guardianPhone(보조 연락처, 있으면 이 번호로 발송)
items[]–배열청구 항목 name(1~20자), price(≥100), discountAmount, discountUnit(AMOUNT/RATE), type. 순액 합계가 amount와 같아야 함. 알림톡·문자에 5개까지 [청구 항목] 목록, 결제 화면에 전부 표시. 예시
billTemplateId–문자열콘솔에 저장한 청구 템플릿 ID
recipientItems[]INDIVIDUAL일 때 ✅배열수신인별 studentName, studentPhone, amount, items[], reason?, description?
relatedSubject · etc–문자열참고 정보(교습과목·메모). 비교육 업종은 생략
JSON
{
  "templateType": "SAME",
  "requestId": "order_20260921_0001",
  "reason": "9월 이용료",
  "description": "9월 30일까지 납부해 주세요.",
  "amount": 128000,
  "sendChannel": "ALIMTALK_THEN_SMS",
  "webhookUrl": "https://api.example.com/caripay/invoice-hook",
  "webhookSecret": "whsec_0123456789abcdef",
  "members": [{ "studentName": "홍길동", "studentPhone": "01012345678" }]
}

응답: { "result_code": 0, "result_msg": "성공", "result_data": null } — 접수. 발송·수납 결과는 조회로 확인합니다.

처리 순서: 청구서 저장(PENDING/발송대기) → 포인트 차감 → 발송 큐 → 게이트웨이 결제 링크 발급 → 알림톡/문자 발송 → 발송완료 + 발송 이력. 게이트웨이 오류·발송 실패 시 청구서는 발송실패로 남고 포인트는 되돌려집니다.

오류 예: 포인트가 부족하여 청구서를 보낼 수 없습니다. · 청구 금액은 최소 100원 이상이어야 합니다. · 같은 requestId(...)로 다른 내용의 청구서를 보낼 수 없습니다. · requestId 멱등 발송은 수신자 1명만 지원합니다.

청구서 목록 조회

HTTP
GET /app/v1/sales/bill?month=2026-09&page=1&size=50
파라미터설명
monthyyyy-MM. 생략 시 전체
page · size1부터, 최대 100

응답 result_data.bills[]의 주요 필드: id, uniqueId, paymentId(거래번호), status(PENDING/DONE/CANCELED), receiver{name,phone}, amount, reason, createDateTime, doneDateTime, firstSentAt, lastSentAt, sendCount, sendChannel, requestId.

청구서 상세 조회

HTTP
GET /app/v1/sales/bill/{id}

{id}는 uniqueId(UUID) 또는 숫자 id입니다.

JSON
{
  "result_code": 0, "result_msg": "성공",
  "result_data": {
    "bill": { "uniqueId": "…", "status": "DONE", "amount": 128000, "reason": "9월 이용료" },
    "payment": { "acceptNumber": "12345678", "payCompany": "신한카드", "installmentMonth": 0, "paymentDateTime": "2026-09-21 12:01:35" },
    "sendInfo": { "firstSentAt": "2026-09-21 12:00:03", "lastSentAt": "2026-09-21 12:00:03", "sendCount": 1 },
    "sendHistories": [
      { "sendType": "INITIAL", "sendResult": "SUCCESS", "sendChannel": "SMS", "sentAt": "2026-09-21 12:00:03", "receiverPhone": "01012345678", "errorMessage": null }
    ]
  }
}
  • sendHistories[].sendChannel — 실제로 나간 수단. ALIMTALK_THEN_SMS로 보냈는데 문자로 대체됐으면 SMS.
  • sendResult는 알리고 접수 결과입니다. 알림톡의 실제 도착 여부는 POST /app/v1/sales/bill/{id}/refresh-status로 갱신합니다.

청구서 재발송

HTTP
POST /app/v1/sales/bill/resend
JSON
{ "billIds": ["{uniqueId}", "{uniqueId}"] }
  • 이미 발송된 미납 청구서만. 같은 거래번호·같은 링크·청구서에 저장된 발송 수단으로 다시 보냅니다.
  • 건당 포인트 차감. 실패한 건은 포인트가 되돌려집니다.
  • 응답 result_data[]는 청구서 요약 목록입니다.

청구서 삭제

HTTP
DELETE /app/v1/sales/bill/{id}

미납(PENDING) 청구서를 삭제합니다. 게이트웨이 청구도 STORE_DELETE로 닫혀 고객이 결제할 수 없습니다.

청구서 취소(환불)

HTTP
PUT /app/v1/sales/bill/{id}

수납완료(DONE) 청구서의 결제를 전액 취소합니다. 카드사 승인취소 후 상태가 CANCELED가 되고 매출 집계가 갱신됩니다. 응답은 상세 조회와 같은 형식입니다.

결제 완료·취소 웹훅

webhookUrl이 있는 청구서가 DONE(결제 완료) 또는 CANCELED(취소)로 바뀌면 그 주소로 POST 합니다.

HTTP
POST {webhookUrl}
Content-Type: application/json
X-CariPay-Event: bill.paid
X-CariPay-Delivery: 1234
X-CariPay-Signature: t=1758430800,v1=ae201a94ae2764a1f463601781a180495c5cdd9de3b7a29c09004cca3a251387
필드설명
eventbill.paid / bill.canceled
billId청구서 uniqueId — GET /app/v1/sales/bill/{id}에 그대로 사용
requestId생성 때 보낸 requestId(없으면 null)
transSeqNo게이트웨이 거래번호
statusDONE / CANCELED
amount · reason청구 금액·사유
paidAt · canceledAt · occurredAtyyyy-MM-dd'T'HH:mm:ss (KST)
  • 귀사 응답 2xx = 성공. 그 외·연결 실패는 1분·5분·30분·2시간 뒤 재시도 후 5회에서 포기.
  • 재시도로 같은 이벤트가 두 번 도달할 수 있습니다. billId+event로 멱등 처리하세요.
  • webhookSecret을 준 청구서에만 X-CariPay-Signature가 붙습니다. v1 = HMAC-SHA256(secret, "<t>.<본문 원문 바이트>") 소문자 hex, t는 전송 시각(unix초). 수신 측은 같은 식으로 계산해 상수 시간 비교하고 |now − t| ≤ 300초를 확인합니다(SDK verifyWebhookSignature). 예시 값: secret whsec_0123456789abcdef, 본문 {"event":"bill.paid"}, t=1758430800 → 위 헤더.
  • 서명 여부와 관계없이 본문만으로 확정하지 말고 getInvoice로 상태를 확인하세요.

공개 청구서 조회

HTTP
GET /app/v1/sales/public/bill/{transSeqNo}

인증 없이 거래번호로 청구 내역을 봅니다. caripay.co.kr/pay/{거래번호} 페이지가 사용합니다. 연락처는 마스킹됩니다.

JSON
{ "result_code": 0, "result_msg": "성공",
  "result_data": { "transSeqNo": "20260921120000Ab12Cd", "status": "PENDING",
    "paymentUrl": "https://chewingpay.com/payments?txId=…", "corpName": "카리학원", "businessName": "카리사업자",
    "receiverName": "홍길동", "receiverPhoneMasked": "010-****-5678", "reason": "9월 이용료", "description": "…",
    "amount": 128000, "issuedAt": "2026-09-21T12:00:03", "paidAt": null, "canceledAt": null,
    "items": [{ "name": "수강료", "price": 128000, "qty": 1 }] } }

없는 거래번호는 HTTP 404 + {"result_code": -10, "result_msg": "청구서를 찾을 수 없습니다."}.

포인트

HTTP
GET /app/v1/points/me

발송 포인트 잔액을 돌려줍니다. 발송 전에 확인해 부족하면 콘솔에서 충전합니다.

문서에 없는 내용이나 오류는 bellight@goatheaven.com 또는 지원 문의로 알려주세요.