API 레퍼런스
청구서 API
청구 서버의 청구서 생성·조회·재발송·삭제·취소와 공개 청구서 조회 규격입니다.
BASE_URL: https://api.dev.caripay.co.kr · 인증 헤더 x-access-token: {accessToken} (공개 청구서 조회 제외)
응답 봉투는 { result_code, result_msg, result_data }이며 result_code: 0만 성공입니다. 요청·응답 규격
청구서 생성·발송
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 | – | 문자열 | 참고 정보(교습과목·메모). 비교육 업종은 생략 |
{
"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명만 지원합니다.
청구서 목록 조회
GET /app/v1/sales/bill?month=2026-09&page=1&size=50| 파라미터 | 설명 |
|---|---|
month | yyyy-MM. 생략 시 전체 |
page · size | 1부터, 최대 100 |
응답 result_data.bills[]의 주요 필드: id, uniqueId, paymentId(거래번호), status(PENDING/DONE/CANCELED), receiver{name,phone}, amount, reason, createDateTime, doneDateTime, firstSentAt, lastSentAt, sendCount, sendChannel, requestId.
청구서 상세 조회
GET /app/v1/sales/bill/{id}{id}는 uniqueId(UUID) 또는 숫자 id입니다.
{
"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로 갱신합니다.
청구서 재발송
POST /app/v1/sales/bill/resend{ "billIds": ["{uniqueId}", "{uniqueId}"] }- 이미 발송된 미납 청구서만. 같은 거래번호·같은 링크·청구서에 저장된 발송 수단으로 다시 보냅니다.
- 건당 포인트 차감. 실패한 건은 포인트가 되돌려집니다.
- 응답
result_data[]는 청구서 요약 목록입니다.
청구서 삭제
DELETE /app/v1/sales/bill/{id}미납(PENDING) 청구서를 삭제합니다. 게이트웨이 청구도 STORE_DELETE로 닫혀 고객이 결제할 수 없습니다.
청구서 취소(환불)
PUT /app/v1/sales/bill/{id}수납완료(DONE) 청구서의 결제를 전액 취소합니다. 카드사 승인취소 후 상태가 CANCELED가 되고 매출 집계가 갱신됩니다. 응답은 상세 조회와 같은 형식입니다.
결제 완료·취소 웹훅
webhookUrl이 있는 청구서가 DONE(결제 완료) 또는 CANCELED(취소)로 바뀌면 그 주소로 POST 합니다.
POST {webhookUrl}
Content-Type: application/json
X-CariPay-Event: bill.paid
X-CariPay-Delivery: 1234
X-CariPay-Signature: t=1758430800,v1=ae201a94ae2764a1f463601781a180495c5cdd9de3b7a29c09004cca3a251387| 필드 | 설명 |
|---|---|
event | bill.paid / bill.canceled |
billId | 청구서 uniqueId — GET /app/v1/sales/bill/{id}에 그대로 사용 |
requestId | 생성 때 보낸 requestId(없으면 null) |
transSeqNo | 게이트웨이 거래번호 |
status | DONE / CANCELED |
amount · reason | 청구 금액·사유 |
paidAt · canceledAt · occurredAt | yyyy-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초를 확인합니다(SDKverifyWebhookSignature). 예시 값: secretwhsec_0123456789abcdef, 본문{"event":"bill.paid"},t=1758430800→ 위 헤더.- 서명 여부와 관계없이 본문만으로 확정하지 말고
getInvoice로 상태를 확인하세요.
공개 청구서 조회
GET /app/v1/sales/public/bill/{transSeqNo}인증 없이 거래번호로 청구 내역을 봅니다. caripay.co.kr/pay/{거래번호} 페이지가 사용합니다. 연락처는 마스킹됩니다.
{ "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": "청구서를 찾을 수 없습니다."}.
포인트
GET /app/v1/points/me발송 포인트 잔액을 돌려줍니다. 발송 전에 확인해 부족하면 콘솔에서 충전합니다.
문서에 없는 내용이나 오류는 bellight@goatheaven.com 또는 지원 문의로 알려주세요.