본문으로 건너뛰기

용어 사전

CROSS Pay API · SDK · Webhook 문서 전반에 자주 등장하는 용어를 한 줄 정의 + 예시 + 어디서 마주치는지 의 세 가지로 정리합니다.


결제 라이프사이클

PaymentIntent

머천트가 결제 1건을 시작하려는 의도(intent) 를 표현하는 서버 측 객체. POST /v1/payments 응답으로 발급됩니다.

  • ID 형식: pay_<22자 base62> (예: pay_4xKqRtJp9aB2c7zNm0)
  • 한 PaymentIntent 는 하나의 결제 시도와 1:1 대응
curl -X POST https://api.crosspay.io/v1/payments \
-H "Authorization: Bearer $CROSS_PAY_API_KEY" \
-d '{"currency":"USD","amount":"9.99","payer_uid":"user-123"}'
# → { "id": "pay_abc123", "status": "PENDING", "checkout_url": "..." }

Checkout

Buyer 가 결제수단을 선택하고 PG 와 상호작용하는 세션. PaymentIntent 와 1:1 매핑. ID 는 cs_<16자 base62> (예: cs_a1b2c3d4e5f6g7h8).

checkout_id 자체가 capability token 역할을 하므로, 브라우저에서 직접 /v1/checkout/{checkout_id} 호출이 가능합니다 — API key 없이.

Quote

특정 결제수단을 선택했을 때의 수수료·세금·총액 견적. SelectQuote 시점에 freeze 되어 결제 종결까지 변경되지 않습니다.

{
"fee_rate": "0.029",
"fee_amount": "1450",
"estimated_tax": "5000",
"total_amount": "56450"
}

Session (PG session)

머천트의 PaymentIntent 와 외부 PG (Worldpay / PayLetter / BinancePay / 온체인) 의 결제건을 묶는 내부 객체. sess_<base62>.

머천트가 직접 다루지 않지만, on-chain 결제의 경우 GET /v1/onchain/sessions/{session_id} 로 컨트랙트 호출 파라미터를 가져옵니다.


결제 상태(PaymentStatus)

전체 상태 머신과 전이 규칙은 Webhooks Overview — 결제 상태 머신.

PENDING

PaymentIntent 생성 직후, quote 선택 전 상태. 이 시점에서만 머천트 cancel API 가 허용됩니다.

PROCESSING

POST /checkout/{id}/quotes (SelectQuote) 가 PG session 을 만든 직후의 외부 PG 인계 구간. PG·체인의 종결 webhook(PAID / FAILED) 또는 expiry 워커(EXPIRED) 를 기다립니다.

머천트 코드 분기 예시:

switch (payment.status) {
case 'PENDING':
return showCheckout(payment.checkout_url)
case 'PROCESSING':
return showWaitingScreen('PG 처리 중 — 결과 대기') // 결제 확정 X
case 'PAID':
return fulfillOrder(payment)
case 'FAILED':
case 'EXPIRED':
case 'CANCELLED':
return showFailureScreen(payment)
}

terminal states

PAID / FAILED / EXPIRED / CANCELLED / PARTIALLY_REFUNDED / REFUNDED. 이후 상태로 전이하지 않습니다 (refund 는 PAID → PARTIALLY_REFUNDED → REFUNDED 가 예외 진행).


인증·보안

Merchant API Key

/v1/payments/** 호출에 필요한 server-side 시크릿. Authorization: Bearer <key> 헤더로 전달. 브라우저에 노출 금지.

샌드박스 키와 운영 키는 prefix 가 분리되어 있습니다.

환경Prefix예시
Sandboxsk_test_sk_test_4xKqRt...
Productionsk_live_sk_live_9aB2c7...

Idempotency-Key

같은 요청이 여러 번 도착해도 한 번만 처리되도록 클라이언트가 발급하는 키. 24시간 동안 Redis 에 캐시되며, 같은 키로 다시 호출하면 첫 응답을 그대로 돌려줍니다.

POST /v1/payments HTTP/1.1
Idempotency-Key: 0190a1b2-c3d4-7e5f-89ab-cdef01234567

같은 키 + 다른 body 로 호출하면 409 IDEMPOTENCY_CONFLICT.

Callback Secret (webhook secret)

머천트 webhook endpoint 의 서명 검증에 사용되는 머천트별 시크릿. CROSS Pay 측에 암호화되어 보관되며 발급은 out-of-band(이메일·파트너 채널).

검증 알고리즘: HMAC-SHA256 over ${webhook-id}.${webhook-timestamp}.${body}. 자세히는 Verifying Webhooks.

MAC2 (Worldpay HPP)

Worldpay Hosted Payment Pages 의 buyer-redirect URL 변조 검증에 쓰이는 HMAC-SHA256 서명. successURL / failureURL / cancelURL 의 쿼리스트링을 키로 계산.


안전장치

FDS (Fraud Detection Service)

/v1/checkout/** 응답 직전에 실행되는 사기 탐지. 차단 시 HTTP 200 으로 fds: { outcome: "DENY", code, message, ... } envelope 만 반환합니다.

{
"fds": {
"outcome": "DENY",
"code": "COUNTRY_BLOCKED",
"risk_level": "HIGH",
"risk_score": 92
}
}

머천트 SDK 는 HTTP status 가 아니라 fds.outcome 으로 분기해야 합니다.

Stale webhook guard

같은 checkout 에서 결제수단을 바꾸면 payment.provider 가 갱신되는데, 옛 PG 가 뒤늦게 콜백을 보내면 서버가 payment.provider 와 webhook 의 PG 가 일치하지 않는다고 판단해 ACK 200 + WARN 으로 무시합니다. 머천트 endpoint 로 stale 종결 이벤트가 도착하지 않습니다.


발송·전달

이벤트 큐

결제 도메인 이벤트가 머천트에 전달되기 전 적재되는 내부 큐. PG 콜백을 받은 트랜잭션과 같은 트랜잭션에서 기록되므로 at-least-once 전달이 보장됩니다.

Standard Webhooks v1

CROSS Pay 가 따르는 webhook envelope 규격 (https://www.standardwebhooks.com). 헤더 3종 (webhook-id, webhook-timestamp, webhook-signature) 으로 식별· 멱등·서명 검증을 모두 처리합니다.

at-least-once · dedup key

webhook 은 같은 이벤트가 최소 한 번 이상 도착할 수 있습니다. 머천트는 webhook-id 헤더 값을 dedup 키로 사용해 중복을 처리해야 합니다.

const seen = await redis.set(`webhook:${webhookId}`, '1', 'NX', 'EX', 86400)
if (!seen) return res.status(200).end() // 이미 처리됨

통화·금액

amount (decimal string)

amount 는 항상 문자열 입니다 (JS Number 정밀도 손실 방지). 통화의 ISO 4217 decimals 자릿수를 초과하면 422 INVALID_AMOUNT.

통화유효 예시
USD"9.99" (decimals=2)
JPY"500" (decimals=0)
USDT @ BSC"10.123456789012345678" (decimals=18)

amount_smallest_unit

온체인 결제에서 토큰 컨트랙트 호출에 그대로 전달하는 정수 문자열 표현. amount × 10^decimals.

amount: "9.9", USDT @ Ethereum (decimals=6)
→ amount_smallest_unit: "9900000"

온체인 결제

PayGateway

CROSS Pay 가 각 체인에 배포한 결제 컨트랙트. buyer 지갑이 직접 호출합니다. ABI 와 주소는 GET /v1/chains/{slug} 로 조회.

pay_uuid

PayGateway.pay(bytes16 uuid, ...) 시그니처에 1:1 대응되는 결제 식별자. 0x + 32 hex (16 bytes) 형식. wallet client 는 getBytes(pay_uuid) 결과를 그대로 컨트랙트 호출에 전달합니다.

finality

블록체인이 트랜잭션을 더 이상 reorg 시키지 않는다고 간주하는 시점. CROSS Pay 가 finality 를 확인한 후에야 payment.completed 이벤트가 발화됩니다. 따라서 paid_at 은 TX 브로드캐스트 시각이 아니라 finality 확정 시각입니다.


운영

추가 용어 제안

위 사전에 빠진 용어가 있으면 GitHub Issues 또는 dev@to.nexus 로 제보해주세요.