API 개요
페이싱크 v2 REST API의 기본 주소, 인증 방식, 응답 형식, 페이지네이션, 시각과 ID 형식을 정리했어요.
페이싱크 API로 주문을 만들고 바꾸고, 입금 내역과 현금영수증을 다룰 수 있어요. 요청과 응답 본문은 JSON이에요. 주문과 입금에 일이 생길 때 바로 알고 싶다면 웹훅을 함께 쓰세요.
기본 정보
| 항목 | 값 |
|---|---|
| 기본 주소 | https://api.paysync.kr |
| 버전 | v2 (모든 경로가 /v2로 시작해요) |
| 인증 | Authorization: Bearer <API 키> |
| 본문 형식 | application/json, UTF-8 |
| 시각 형식 | Unix 초(정수). 예: 1777346055 |
| 날짜 필터 형식 | YYYY-MM-DD, 한국 시간(KST) 기준 |
| 금액 | 원 단위 정수, 부가세 포함 |
| OpenAPI 명세 | /openapi.json |
인증
대시보드 API 키에서 만든 키를 Authorization 헤더에 넣어요. API 키는 sk_live_로 시작해요.
Authorization: Bearer sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
API 키는 워크스페이스 하나에 속해요. 키로 보낸 요청은 그 워크스페이스의 주문, 입금, 현금영수증만 다뤄요. 대시보드처럼 X-Workspace-Id 헤더를 보낼 필요는 없어요.
| 상황 | 응답 |
|---|---|
Authorization 헤더가 없어요. |
401, 80003 |
Bearer가 아닌 인증 방식이에요. |
401, 80001 |
| 키가 틀렸거나, 만료됐거나, 삭제됐거나, 꺼져 있어요. | 401, 290006 |
| 읽기 전용 키로 쓰기 요청을 보냈어요. | 403, 290007 |
| API 키로 쓸 수 없는 대시보드 전용 요청이에요. | 403, 80002 또는 80008 |
주문 하나를 만드는 요청이에요.
curl -X POST https://api.paysync.kr/v2/invoices \
-H "Authorization: Bearer $PAYSYNC_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer": {
"name": "홍길동",
"email": "hong@example.com",
"phoneNumber": "01012345678"
},
"amount": 50000,
"expireAfterDays": 1,
"metadata": { "orderId": "ORDER-2026-0001" }
}'const res = await fetch("https://api.paysync.kr/v2/invoices", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PAYSYNC_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
customer: {
name: "홍길동",
email: "hong@example.com",
phoneNumber: "01012345678",
},
amount: 50000,
expireAfterDays: 1,
metadata: { orderId: "ORDER-2026-0001" },
}),
});
const { code, data } = await res.json();import os
import requests
res = requests.post(
"https://api.paysync.kr/v2/invoices",
headers={"Authorization": f"Bearer {os.environ['PAYSYNC_API_KEY']}"},
json={
"customer": {
"name": "홍길동",
"email": "hong@example.com",
"phoneNumber": "01012345678",
},
"amount": 50000,
"expireAfterDays": 1,
"metadata": {"orderId": "ORDER-2026-0001"},
},
)
print(res.json())import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.json.*
val client = HttpClient(CIO) {
install(ContentNegotiation) { json() }
}
val response = client.post("https://api.paysync.kr/v2/invoices") {
bearerAuth(System.getenv("PAYSYNC_API_KEY"))
contentType(ContentType.Application.Json)
setBody(buildJsonObject {
putJsonObject("customer") {
put("name", "홍길동")
put("email", "hong@example.com")
put("phoneNumber", "01012345678")
}
put("amount", 50000)
put("expireAfterDays", 1)
putJsonObject("metadata") { put("orderId", "ORDER-2026-0001") }
})
}
println(response.bodyAsText())import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class CreateInvoice {
public static void main(String[] args) throws Exception {
String body = """
{
"customer": {
"name": "홍길동",
"email": "hong@example.com",
"phoneNumber": "01012345678"
},
"amount": 50000,
"expireAfterDays": 1,
"metadata": { "orderId": "ORDER-2026-0001" }
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.paysync.kr/v2/invoices"))
.header("Authorization", "Bearer " + System.getenv("PAYSYNC_API_KEY"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), reqwest::Error> {
let api_key = std::env::var("PAYSYNC_API_KEY").expect("PAYSYNC_API_KEY");
let body = json!({
"customer": {
"name": "홍길동",
"email": "hong@example.com",
"phoneNumber": "01012345678"
},
"amount": 50000,
"expireAfterDays": 1,
"metadata": { "orderId": "ORDER-2026-0001" }
});
let response = reqwest::Client::new()
.post("https://api.paysync.kr/v2/invoices")
.bearer_auth(api_key)
.json(&body)
.send()
.await?
.text()
.await?;
println!("{response}");
Ok(())
}API 키 권한
API 키를 만들 때 권한을 골라요.
| 권한 | 할 수 있는 일 |
|---|---|
| 읽기·쓰기 | 주문, 입금, 현금영수증 조회와 주문 생성, 수정, 결제 완료 처리, 취소, 현금영수증 발급, 재발급, 취소, 전송 |
| 읽기 전용 | 조회만 해요. 쓰기 요청에는 403, 290007이 와요. |
계좌, 웹훅, 멤버, 구독 같은 워크스페이스 설정은 API 키로 바꿀 수 없어요. 대시보드에서 바꿔요.
API 키 계좌 범위
API 키를 만들 때 계좌 범위를 고른 계좌만으로 정하면 그 키로 다룰 수 있는 주문과 입금이 좁혀져요. 모든 계좌로 만든 키에는 제한이 없어요.
| API | 계좌를 제한한 키의 동작 |
|---|---|
| 주문 생성 | bankAccountIds에 허용된 계좌만 넣을 수 있어요. 빈 배열(모든 계좌로 받기)로는 만들 수 없어요. |
| 주문 조회, 수정, 결제 완료 처리, 취소 | bankAccountIds가 모두 허용된 계좌인 주문만 다뤄요. 모든 계좌로 받는 주문은 다룰 수 없어요. |
| 주문 목록 | 위 조건에 맞는 주문만 나와요. |
| 입금 조회와 목록 | 허용된 계좌로 들어온 입금만 나와요. |
| 현금영수증 | 계좌와 관계가 없어서 제한하지 않아요. |
허용되지 않은 주문이나 입금에 접근하면 403, 80002가 와요.
응답 형식
모든 응답은 code를 담아요. code는 처리 결과를 나타내는 숫자 문자열이고, HTTP 상태 코드와 함께 와요. 성공하면 "10001"이에요.
| 응답 종류 | 형식 |
|---|---|
| 단건 | { "code", "data" } |
| 목록 | { "code", "items", "totalItems" } |
| 데이터 없음 | { "code" } |
{
"code": "10001",
"data": {
"id": "ivc_a1b2c3d4e5f6g7h8i9j0k1l2",
"number": 1043,
"status": "PENDING",
"customer": {
"name": "홍길동",
"email": "hong@example.com",
"phoneNumber": "01012345678"
},
"amount": 50000,
"...": "..."
}
}
{
"code": "220003"
}
일부 오류는 처리에 필요한 정보를 data에 담아요. 예를 들어 같은 주문이 이미 있으면 기존 주문 ID를 함께 알려 줘요.
{
"code": "220010",
"data": { "invoiceId": "ivc_n0o1p2q3r4s5t6u7v8w9x0y1", "number": 1042 }
}
코드 목록은 에러 코드에 있어요. 응답 객체에는 새 필드가 추가될 수 있으니, 모르는 필드는 무시하도록 만들어 주세요.
페이지네이션
목록 조회는 offset과 limit 쿼리 파라미터로 페이지를 나눠요.
| 파라미터 | 타입 | 설명 |
|---|---|---|
offset |
integer | 건너뛸 항목 수예요. 0 이상이에요. |
limit |
integer | 가져올 항목 수예요. 1~100이에요. |
주문과 입금 목록에서는 두 값이 필수예요. 현금영수증 목록에서 빼면 offset=0, limit=100으로 조회해요. 목록 응답의 totalItems는 조건에 맞는 전체 항목 수예요.
{
"code": "10001",
"items": [
{ "id": "trx_a1b2c3d4e5f6g7h8i9j0k1l2", "depositorName": "홍길동", "amount": 50000, "...": "..." }
],
"totalItems": 142
}
필터
- 날짜 필터
dateFrom,dateTo는YYYY-MM-DD형식의 한국 시간 날짜예요. 두 날짜 모두 결과에 포함돼요.dateFrom=2026-04-01&dateTo=2026-04-30은 4월 1일 0시부터 4월 30일 24시(KST)까지예요. status처럼 여러 값을 받는 필터는 쉼표로 이어 보내거나(status=PENDING,EXPIRED) 파라미터를 반복해서 보내요(status=PENDING&status=EXPIRED).
시각 형식
API 응답의 시각은 Unix 초 단위 정수예요. 요청 본문의 expiresAt도 Unix 초로 보내요. 웹훅 페이로드의 시각만 ISO 8601 문자열이에요.
ID 형식
모든 ID는 리소스 접두사 뒤에 영문 소문자와 숫자 24자가 붙어요.
| 접두사 | 리소스 |
|---|---|
ivc_ |
주문 |
trx_ |
입금 |
crt_ |
현금영수증 |
bac_ |
은행 계좌 |
acc_ |
페이싱크 계정 |
apk_ |
API 키 |
whd_ |
웹훅 |
whm_ |
웹훅 전송 |
evt_ |
웹훅 이벤트 |
주문에는 ID와 별개로 워크스페이스마다 1001부터 매기는 주문번호(number)가 있어요. 대시보드와 구매자 메일에는 #1043처럼 주문번호가 보여요.
요청 기록
API 키로 보낸 요청은 대시보드 API 키의 요청 기록에 30일 동안 남아요. 메서드, 경로, HTTP 상태, 오류 코드, 처리 시간, IP 주소를 볼 수 있어요. 요청 본문과 응답 본문은 남기지 않아요.
엔드포인트
| 메서드 | 경로 | 설명 |
|---|---|---|
POST |
/v2/invoices |
주문 생성 |
GET |
/v2/invoices |
주문 목록 조회 |
GET |
/v2/invoices/{id} |
주문 단건 조회 |
PATCH |
/v2/invoices/{id} |
주문 수정 |
POST |
/v2/invoices/{id}/mark-paid |
주문 결제 완료 처리 |
POST |
/v2/invoices/{id}/cancel |
주문 취소 |
GET |
/v2/transactions |
입금 내역 목록 조회 |
GET |
/v2/transactions/{id} |
입금 단건 조회 |
POST |
/v2/cash-receipts |
현금영수증 발급 |
GET |
/v2/cash-receipts |
현금영수증 목록 조회 |
GET |
/v2/cash-receipts/{id} |
현금영수증 단건 조회 |
POST |
/v2/cash-receipts/{id}/cancel |
현금영수증 취소 |
POST |
/v2/cash-receipts/{id}/reissue |
현금영수증 재발급 |
GET |
/v2/cash-receipts/{id}/urls |
현금영수증 문서 주소 조회 |
POST |
/v2/cash-receipts/{id}/send-email |
현금영수증 이메일 전송 |