발급 관리
PIN 발급과 쿠폰 발송에 공통으로 적용되는 조회, 취소, 재발송, 이미지 조회 API를 설명합니다.
발급 상태 라이프사이클
쿠폰의 상태는 다음과 같이 전이됩니다.
쿠폰 상태
| 상태 | 설명 |
|---|---|
PENDING | 발급 처리 중 |
ISSUED | 발급 완료, 사용 가능 |
USED | 사용 완료 |
CANCELED | 취소됨 |
EXPIRED | 유효기간 만료 |
INACTIVE | 비활성 (벤더 측 이상) |
FAIL | 발급 실패 |
메시지 상태 (SEND 타입만 해당)
| 상태 | 설명 |
|---|---|
PENDING | 발송 대기 중 |
REQUESTED | 벤더에 발송 요청됨 |
SENT | 발송 완료 |
FAILED | 발송 실패 |
RESENT | 재발송 완료 |
발급 조회
/v1/coupons/issued발급 결과를 조회합니다. id 또는 orderId 중 하나를 지정해야 합니다. PIN 발급과 쿠폰 발송 모두 이 엔드포인트로 조회합니다.
Query Parameters
idstring발급 ID. iss_ 접두사로 시작합니다.
orderIdstring발급 시 전달한 고객사 주문 ID
imageTtlDaysinteger응답에 포함되는 이미지 URL의 유효기간(일). 기본 1일, 최대 365일.기본값: 1
id와 orderId 중 정확히 하나만 지정해야 합니다. 둘 다 지정하거나 둘 다 생략하면 400 에러가 반환됩니다.
Response Body
idstring필수발급 식별자 (iss_ 접두사)
couponIdstring필수쿠폰 식별자
orderIdstring | null필수고객사 주문 ID
orderNumberstring필수고객 응대용 주문 번호
pricenumber필수정가 (원). 쿠폰의 액면가입니다.
purchasePricenumber필수실구매가 (원). 계약 할인율을 적용한 금액이며, 적용 가능한 할인이 없으면 정가와 같습니다. 발급 시점 기준으로 고정됩니다.
typestring필수발급 유형
PINSENDcouponobject필수쿠폰 상태 정보
statusstring필수쿠폰 상태
PENDINGISSUEDUSEDCANCELEDEXPIREDINACTIVEFAILpinNumberstring | null필수PIN/바코드 번호
validityobject | null필수쿠폰 유효기간
fromstring | null필수유효 시작일 (KST, YYYY-MM-DD)
tostring | null필수유효 종료일 (KST, YYYY-MM-DD)
reasonstring | null필수취소 또는 발급 실패 사유
issuedAtstring | null필수발급 완료 시각 (ISO 8601)
usedAtstring | null필수사용 시각 (ISO 8601)
canceledAtstring | null필수취소 시각 (ISO 8601)
messageobject | null필수메시지 발송 정보. PIN 타입에서는 null입니다.
statusstring필수메시지 발송 상태
PENDINGREQUESTEDSENTFAILEDRESENTtitlestring | null필수메시지 제목
contentstring | null필수메시지 본문
senderNumberstring | null필수발신번호
receiverNumberstring | null필수수신자 전화번호
receiverNamestring | null필수수신자 이름
reasonstring | null필수메시지 발송 실패 사유
sentAtstring | null필수발송 시각 (ISO 8601)
imageUrlstring | null필수Pre-signed 이미지 URL. PIN 타입에서만 제공되며, 브라우저나 <img> 태그에서 인증 없이 직접 사용할 수 있습니다. imageTtlDays에 따라 유효기간이 설정됩니다.
couponViewUrlstring | null필수쿠폰 확인 페이지 링크. SEND 타입에서 수신자에게 발송되는 것과 동일한 주소이며, 인증 없이 쿠폰번호·바코드·이미지를 확인할 수 있습니다. 아직 발급되지 않았거나 발급에 실패한 건은 null입니다.
createdAtstring필수발급 요청 시각 (ISO 8601)
요청 예시
- cURL
- Node.js
- Python
- Java
# id로 조회
curl -u "test_sk_your_key_here:" \
"https://api.aiconbiz.kr/v1/coupons/issued?id=iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a"
# orderId로 조회
curl -u "test_sk_your_key_here:" \
"https://api.aiconbiz.kr/v1/coupons/issued?orderId=ORD-20260318-0001"
const secretKey = 'test_sk_your_key_here';
const encoded = Buffer.from(`${secretKey}:`).toString('base64');
const res = await fetch(
'https://api.aiconbiz.kr/v1/coupons/issued?id=iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a',
{ headers: { 'Authorization': `Basic ${encoded}` } },
);
const data = await res.json();
console.log(data.type); // PIN or SEND
console.log(data.coupon.status); // ISSUED, CANCELED, USED, ...
import base64
import requests
secret_key = "test_sk_your_key_here"
encoded = base64.b64encode(f"{secret_key}:".encode()).decode()
res = requests.get(
"https://api.aiconbiz.kr/v1/coupons/issued",
headers={"Authorization": f"Basic {encoded}"},
params={"id": "iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a"},
)
data = res.json()
print(data["type"]) # PIN or SEND
print(data["coupon"]["status"]) # ISSUED, CANCELED, USED, ...
import java.net.URI;
import java.net.http.*;
import java.util.Base64;
String secretKey = "test_sk_your_key_here";
String encoded = Base64.getEncoder()
.encodeToString((secretKey + ":").getBytes());
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(
"https://api.aiconbiz.kr/v1/coupons/issued?id=iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a"))
.header("Authorization", "Basic " + encoded)
.GET()
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
응답 예시 (PIN 타입)
{
"id": "iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a",
"couponId": "cpn_01JNX8D7W7F6J0QYJ7YQ6G7M2R",
"orderId": "ORD-20260318-0001",
"orderNumber": "123456789012",
"price": 4500,
"purchasePrice": 4275,
"type": "PIN",
"coupon": {
"status": "ISSUED",
"pinNumber": "1234-5678-9012",
"validity": {
"from": "2026-03-18",
"to": "2026-04-17"
},
"reason": null,
"issuedAt": "2026-03-18T03:00:03.000+09:00",
"usedAt": null,
"canceledAt": null
},
"message": null,
"imageUrl": "https://api.aiconbiz.kr/v1/coupons/issued/image?id=iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a&expires=1711411200&sig=a1b2c3d4...",
"couponViewUrl": "https://coupon.aiconbiz.kr/c/018d8f3a-2b4c-5d6e-7f8a-9b0c1d2e3f4a?code=9f2c1d7e8a3b4c5d6e7f8a9b0c1d2e3f",
"createdAt": "2026-03-18T03:00:00.000+09:00"
}
응답 예시 (SEND 타입)
{
"id": "iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a",
"couponId": "cpn_01JNX8D7W7F6J0QYJ7YQ6G7M2R",
"orderId": "ORD-20260323-0001",
"orderNumber": "123456789012",
"price": 4500,
"purchasePrice": 4275,
"type": "SEND",
"coupon": {
"status": "ISSUED",
"pinNumber": null,
"validity": {
"from": "2026-03-23",
"to": "2026-04-22"
},
"reason": null,
"issuedAt": "2026-03-23T03:00:03.000+09:00",
"usedAt": null,
"canceledAt": null
},
"message": {
"status": "SENT",
"title": "쿠폰이 도착했습니다",
"content": "회원가입을 축하합니다!",
"senderNumber": "01011112222",
"receiverNumber": "01012345678",
"receiverName": "홍길동",
"reason": null,
"sentAt": "2026-03-23T03:00:05.000+09:00"
},
"imageUrl": null,
"couponViewUrl": "https://coupon.aiconbiz.kr/c/018d8f3a-2b4c-5d6e-7f8a-9b0c1d2e3f4a?code=9f2c1d7e8a3b4c5d6e7f8a9b0c1d2e3f",
"createdAt": "2026-03-23T03:00:00.000+09:00"
}
에러 응답
| 코드 | HTTP | 설명 |
|---|---|---|
COUPON_INVALID_ISSUANCE_ID | 400 | 발급 ID 형식이 올바르지 않습니다. |
COUPON_ISSUANCE_NOT_FOUND | 404 | 발급 내역을 찾을 수 없습니다. |
이 외에 인증, 요청 형식 관련 공통 에러가 발생할 수 있습니다.
발급 취소
/v1/coupons/issued/cancel발급 또는 발송된 쿠폰을 취소합니다. id 또는 orderId 중 하나를 지정해야 합니다. ISSUED 상태인 쿠폰만 취소할 수 있습니다.
Request Body
요청 파라미터
idstring발급 ID. iss_ 접두사로 시작합니다.
orderIdstring발급 시 전달한 고객사 주문 ID
reasonstring필수취소 사유. 최소 1자, 최대 500자.
id와 orderId 중 정확히 하나만 지정해야 합니다. 둘 다 지정하거나 둘 다 생략하면 400 에러가 반환됩니다.
Response Body
idstring필수취소된 발급 식별자
canceledAtstring필수취소 처리 시각 (ISO 8601)
요청 예시
- cURL
- Node.js
- Python
- Java
# id로 취소
curl -X POST https://api.aiconbiz.kr/v1/coupons/issued/cancel \
-u "test_sk_your_key_here:" \
-H "Content-Type: application/json" \
-d '{
"id": "iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a",
"reason": "고객 요청에 의한 취소"
}'
# orderId로 취소
curl -X POST https://api.aiconbiz.kr/v1/coupons/issued/cancel \
-u "test_sk_your_key_here:" \
-H "Content-Type: application/json" \
-d '{
"orderId": "ORD-20260318-0001",
"reason": "고객 요청에 의한 취소"
}'
const secretKey = 'test_sk_your_key_here';
const encoded = Buffer.from(`${secretKey}:`).toString('base64');
const res = await fetch('https://api.aiconbiz.kr/v1/coupons/issued/cancel', {
method: 'POST',
headers: {
'Authorization': `Basic ${encoded}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: 'iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a',
reason: '고객 요청에 의한 취소',
}),
});
const data = await res.json();
console.log(data.canceledAt); // 2026-03-18T12:00:00.000Z
import base64
import requests
secret_key = "test_sk_your_key_here"
encoded = base64.b64encode(f"{secret_key}:".encode()).decode()
res = requests.post(
"https://api.aiconbiz.kr/v1/coupons/issued/cancel",
headers={
"Authorization": f"Basic {encoded}",
"Content-Type": "application/json",
},
json={
"id": "iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a",
"reason": "고객 요청에 의한 취소",
},
)
data = res.json()
print(data["canceledAt"]) # 2026-03-18T12:00:00.000Z
import java.net.URI;
import java.net.http.*;
import java.util.Base64;
String secretKey = "test_sk_your_key_here";
String encoded = Base64.getEncoder()
.encodeToString((secretKey + ":").getBytes());
String body = """
{
"id": "iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a",
"reason": "고객 요청에 의한 취소"
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.aiconbiz.kr/v1/coupons/issued/cancel"))
.header("Authorization", "Basic " + encoded)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
응답 예시
{
"id": "iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a",
"canceledAt": "2026-03-18T12:00:00.000Z"
}
에러 응답
| 코드 | HTTP | 설명 |
|---|---|---|
COUPON_INVALID_ISSUANCE_ID | 400 | 발급 ID 형식이 올바르지 않습니다. |
COUPON_ISSUANCE_NOT_FOUND | 404 | 발급 내역을 찾을 수 없습니다. |
COUPON_ALREADY_CANCELED | 409 | 이미 취소된 쿠폰입니다. |
COUPON_NOT_CANCELABLE | 409 | 취소할 수 없는 상태입니다. |
COUPON_CANCEL_VENDOR_FAILED | 502 | 쿠폰 취소에 실패했습니다. |
이 외에 인증, 요청 형식 관련 공통 에러가 발생할 수 있습니다.
메시지 재발송
/v1/coupons/issued/resend발송 실패 또는 발급 완료 상태인 쿠폰을 재발송합니다. id 또는 orderId 중 하나를 지정해야 합니다. SEND 타입의 발급 건에만 사용할 수 있습니다.
Request Body
요청 파라미터
idstring발급 ID. iss_ 접두사로 시작합니다.
orderIdstring발급 시 전달한 고객사 주문 ID
id와 orderId 중 정확히 하나만 지정해야 합니다. 둘 다 지정하거나 둘 다 생략하면 400 에러가 반환됩니다.
Response Body
issuanceIdstring필수발급 식별자
resentAtstring필수재발송 시각 (ISO 8601)
요청 예시
- cURL
- Node.js
- Python
- Java
curl -X POST https://api.aiconbiz.kr/v1/coupons/issued/resend \
-u "test_sk_your_key_here:" \
-H "Content-Type: application/json" \
-d '{
"id": "iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a"
}'
const secretKey = 'test_sk_your_key_here';
const encoded = Buffer.from(`${secretKey}:`).toString('base64');
const res = await fetch('https://api.aiconbiz.kr/v1/coupons/issued/resend', {
method: 'POST',
headers: {
'Authorization': `Basic ${encoded}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: 'iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a',
}),
});
const data = await res.json();
console.log(data.resentAt); // 2026-03-23T15:30:00.000Z
import base64
import requests
secret_key = "test_sk_your_key_here"
encoded = base64.b64encode(f"{secret_key}:".encode()).decode()
res = requests.post(
"https://api.aiconbiz.kr/v1/coupons/issued/resend",
headers={
"Authorization": f"Basic {encoded}",
"Content-Type": "application/json",
},
json={
"id": "iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a",
},
)
data = res.json()
print(data["resentAt"]) # 2026-03-23T15:30:00.000Z
import java.net.URI;
import java.net.http.*;
import java.util.Base64;
String secretKey = "test_sk_your_key_here";
String encoded = Base64.getEncoder()
.encodeToString((secretKey + ":").getBytes());
String body = """
{
"id": "iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a"
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.aiconbiz.kr/v1/coupons/issued/resend"))
.header("Authorization", "Basic " + encoded)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = client.send(
request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
응답 예시
{
"issuanceId": "iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a",
"resentAt": "2026-03-23T15:30:00.000Z"
}
에러 응답
| 코드 | HTTP | 설명 |
|---|---|---|
COMMON_ISSUANCE_SUSPENDED | 503 | 쿠폰 발급이 일시적으로 중단되었습니다. 잠시 후 다시 시도해 주세요. |
COUPON_INVALID_ISSUANCE_ID | 400 | 발급 ID 형식이 올바르지 않습니다. |
COUPON_ISSUANCE_NOT_FOUND | 404 | 발급 내역을 찾을 수 없습니다. |
COUPON_RESEND_NOT_ALLOWED | 409 | 재발송할 수 없는 상태입니다. |
COUPON_RESEND_VENDOR_FAILED | 502 | 재발송에 실패했습니다. |
이 외에 인증, 요청 형식 관련 공통 에러가 발생할 수 있습니다.
발급 이미지 조회
/v1/coupons/issued/image발급된 쿠폰의 이미지를 PNG 형식으로 조회합니다. 두 가지 인증 방식을 지원합니다.
발급 직후에는 이미지 생성에 수 초가 소요될 수 있습니다. 아직 생성되지 않은 경우 404를 반환합니다.
인증 방식
이 엔드포인트는 두 가지 인증 방식을 지원합니다. 용도에 따라 적합한 방식을 선택하세요.
| Basic Auth | Pre-signed URL | |
|---|---|---|
| 인증 방법 | Authorization 헤더에 API 키 | URL에 expires + sig 쿼리 파라미터 포함 |
| 용도 | 서버에서 이미지 다운로드 | 브라우저 / <img> 태그 / 앱에서 직접 표시 |
| API 키 노출 | 서버 측에서만 사용 (안전) | 불필요 (URL 자체가 인증) |
| 유효기간 | API 키가 유효한 동안 | expires에 지정된 시각까지 |
방식 1: Basic Auth (서버 간 통신)
기존 API 키 인증 방식입니다. 서버에서 이미지를 다운로드하여 저장하거나 가공할 때 사용합니다.
GET /v1/coupons/issued/image?id=iss_xxx
Authorization: Basic {base64(secretKey:)}
방식 2: Pre-signed URL (브라우저 / 프론트엔드)
발급 조회 응답의 imageUrl 필드에 포함된 URL을 그대로 사용합니다. 인증 헤더가 필요 없으므로 <img> 태그, 브라우저 주소창 등에서 바로 이미지를 표시할 수 있습니다.
<!-- 발급 조회 응답의 imageUrl을 그대로 사용 -->
<img src="https://api.aiconbiz.kr/v1/coupons/issued/image?id=iss_xxx&expires=1711411200&sig=a1b2c3d4..." />
imageUrl의 유효기간은 발급 조회 시 imageTtlDays 파라미터로 설정할 수 있습니다 (기본 1일, 최대 365일). 만료된 URL로 접근하면 401 에러가 반환됩니다. 필요하면 발급 조회를 다시 호출하여 새 URL을 받으세요.
Query Parameters
idstring발급 ID. iss_ 접두사로 시작합니다.
orderIdstring발급 시 전달한 고객사 주문 ID
expiresstringPre-signed URL 만료 시각 (Unix timestamp). Pre-signed URL 방식에서만 사용합니다.
sigstringPre-signed URL 서명. Pre-signed URL 방식에서만 사용합니다.
id와 orderId 중 정확히 하나만 지정해야 합니다.
Response
- Content-Type:
image/png - Cache-Control:
private, max-age=86400
응답 본문은 PNG 이미지 바이너리입니다.
요청 예시 — Basic Auth
- cURL
- Node.js
- Python
- Java
curl -u "test_sk_your_key_here:" \
"https://api.aiconbiz.kr/v1/coupons/issued/image?id=iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a" \
--output coupon-image.png
import { writeFile } from 'fs/promises';
const secretKey = 'test_sk_your_key_here';
const encoded = Buffer.from(`${secretKey}:`).toString('base64');
const res = await fetch(
'https://api.aiconbiz.kr/v1/coupons/issued/image?id=iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a',
{ headers: { 'Authorization': `Basic ${encoded}` } },
);
const buffer = Buffer.from(await res.arrayBuffer());
await writeFile('coupon-image.png', buffer);
import base64
import requests
secret_key = "test_sk_your_key_here"
encoded = base64.b64encode(f"{secret_key}:".encode()).decode()
res = requests.get(
"https://api.aiconbiz.kr/v1/coupons/issued/image",
headers={"Authorization": f"Basic {encoded}"},
params={"id": "iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a"},
)
with open("coupon-image.png", "wb") as f:
f.write(res.content)
import java.net.URI;
import java.net.http.*;
import java.nio.file.*;
import java.util.Base64;
String secretKey = "test_sk_your_key_here";
String encoded = Base64.getEncoder()
.encodeToString((secretKey + ":").getBytes());
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(
"https://api.aiconbiz.kr/v1/coupons/issued/image?id=iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a"))
.header("Authorization", "Basic " + encoded)
.GET()
.build();
HttpResponse<Path> response = client.send(
request, HttpResponse.BodyHandlers.ofFile(Path.of("coupon-image.png")));
요청 예시 — Pre-signed URL
발급 조회 응답의 imageUrl을 그대로 사용합니다. 인증 헤더가 필요 없습니다.
- HTML
- cURL
- Node.js
<!-- 발급 조회 응답의 imageUrl을 src에 그대로 사용 -->
<img src="https://api.aiconbiz.kr/v1/coupons/issued/image?id=iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a&expires=1711411200&sig=a1b2c3d4..." />
# 인증 헤더 없이 URL만으로 접근
curl "https://api.aiconbiz.kr/v1/coupons/issued/image?id=iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a&expires=1711411200&sig=a1b2c3d4..." \
--output coupon-image.png
// 발급 조회로 imageUrl 획득
const secretKey = 'test_sk_your_key_here';
const encoded = Buffer.from(`${secretKey}:`).toString('base64');
const statusRes = await fetch(
'https://api.aiconbiz.kr/v1/coupons/issued?id=iss_018d8f3a2b4c5d6e7f8a9b0c1d2e3f4a&imageTtlDays=30',
{ headers: { 'Authorization': `Basic ${encoded}` } },
);
const { imageUrl } = await statusRes.json();
// imageUrl을 프론트엔드에 전달하면 인증 없이 바로 표시 가능
console.log(imageUrl);
// → https://api.aiconbiz.kr/v1/coupons/issued/image?id=iss_...&expires=...&sig=...
에러 응답
| 코드 | HTTP | 설명 |
|---|---|---|
AUTH_INVALID_PRESIGNED_URL | 401 | 유효하지 않거나 만료된 URL입니다. |
COUPON_INVALID_ISSUANCE_ID | 400 | 발급 ID 형식이 올바르지 않습니다. |
COUPON_ISSUANCE_NOT_FOUND | 404 | 발급 내역을 찾을 수 없습니다. |
COUPON_IMAGE_NOT_READY | 404 | 이미지가 아직 생성되지 않았습니다. |
COUPON_IMAGE_NOT_SUPPORTED | 400 | 이미지를 지원하지 않는 쿠폰입니다. |
이 외에 인증, 요청 형식 관련 공통 에러가 발생할 수 있습니다.