kemBusiness
플랫폼제품작동 방식급여 지급가격개발자자주 묻는 질문
로그인시작하기↗

개발자 문서

Kem Business API로 USDT 결제를 받기 위해 필요한 모든 것: 인증, 결제 엔드포인트, 그리고 주문 상태를 이끄는 서명된 웹훅.

인증결제오류와 한도웹훅테스트

인증

대시보드의 「API 키」에서 키를 만들고, 모든 요청에 시크릿 키를 Bearer token으로 보내세요. 테스트 키(sk_test_…)는 테스트 결제를 만들고, 라이브 키(sk_live_…)는 실제 돈을 움직입니다.

Authorization: Bearer sk_live_...   # or sk_test_...
Base URL: https://api-business.kemapp.io

결제

결제를 생성하고 고객을 호스팅된 checkout_url로 보내세요 — 지갑·네트워크·확인은 Kem이 처리합니다. 결제를 조회하거나, 더 좋게는 웹훅으로 상태를 추적하세요.

POST/v1/payments
curl -X POST https://api-business.kemapp.io/v1/payments \
  -H "Authorization: Bearer sk_test_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1042" \
  -d '{
    "amount": "25.000000",
    "currency": "USDT",
    "merchant_reference": "order-1042",
    "customer_email": "[email protected]",
    "description": "Pro plan",
    "return_url": "https://yourshop.example/thanks",
    "metadata": {"order_id": "1042"}
  }'
{
  "id": "pay_01J...",
  "status": "pending",
  "mode": "test",
  "amount": "25.000000",
  "amount_minor": 25000000,
  "amount_refunded_minor": 0,
  "fee_bps": null,
  "fee_minor": null,
  "net_minor": null,
  "currency": "USDT",
  "network": null,
  "merchant_reference": "order-1042",
  "checkout_url": "https://pay.kemapp.io/pay_01J...",
  "checkout_expires_at": "2026-07-13T13:30:00+00:00",
  "transaction_id": null,
  "detected_at": null,
  "confirmation_pending": false,
  "created_at": "2026-07-13T13:00:00+00:00",
  "updated_at": "2026-07-13T13:00:00+00:00"
}

Idempotency-Key — 선택이지만 권장 — 같은 키로 재시도하면 중복 생성 대신 원래 결제가 반환됩니다.

GET/v1/payments— query: status, limit (1–100, default 20), cursor · returns has_more, next_cursor
GET/v1/payments/{id}

amount — decimal string with 6 places ("25.000000"); amount_minor — the same value as an integer in micro-USDT.

fee_minor and net_minor are null while a payment is in flight and are frozen when it succeeds. Reconcile your payout against net_minor, not amount_minor — the difference is our fee (fee_bps).

결제 라이프사이클

pending → detected → succeeded · failed · expired

pending — 이체 대기 · detected — 온체인에서 감지, 확인 중 · succeeded — 지갑에 자금 확정(이 이벤트에 주문 처리) · failed / expired — 종결. 환불 변화는 웹훅 이벤트로 도착합니다.

checkout window: 30 minutes, then → expired

오류와 한도

모든 오류는 하나의 envelope을 씁니다. 코드는 안정적입니다 — 메시지가 아니라 error.code로 분기하세요.

HTTP 4xx/5xx
{
  "error": {
    "code": "idempotency_conflict",
    "message": "Idempotency-Key reused with a different request"
  }
}
401 unauthorizedmissing or invalid API key
404 payment_not_foundunknown payment id (or a live id with a test key)
409 idempotency_conflictIdempotency-Key reused with a different body — identical retries replay the original response
422 validation_errormalformed body — bad amount, unsupported currency. message reads “{field}: {reason}”
429 rate_limitedover the per-key budget: 100 writes/min, 1000 reads/min

상품, 결제 링크, 웹훅 엔드포인트, 환불은 대시보드에서 관리합니다 — 아직 공개 REST 엔드포인트가 없습니다.

웹훅

대시보드 「Webhooks」에서 엔드포인트를 추가하고 필요한 이벤트를 고르세요. 엔드포인트마다 whsec_… 서명 시크릿이 발급되며 생성 시 한 번만 표시됩니다.

payment.createdA payment intent was created (API or checkout link).
payment.detectedThe transfer was seen on-chain / in the KEM ledger; confirming.
payment.succeededFunds are confirmed in your business wallet. Fulfill on this event.
payment.failedThe payment failed.
payment.expiredThe checkout window closed without payment.
payment.confirmation_delayedThe customer paid, but it couldn't be confirmed inside the checkout window. Don't treat this as expired — hold the order.
payment.refund.createdA refund was initiated from the dashboard.
payment.refund.succeededThe refund settled back to the customer.

이벤트 페이로드

{
  "id": "payment_event_01J...",
  "type": "payment.succeeded",
  "created": "2026-07-13T13:04:12+00:00",
  "data": {
    "payment": {
      "id": "pay_01J...",
      "status": "succeeded",
      "amount_minor": 25000000,
      "currency": "USDT",
      "merchant_reference": "order-1042",
      "network": "TRON",
      "product_id": null,
      "payment_link_id": null
    }
  }
}

서명 검증

모든 전송에는 Kem-Signature 헤더가 있습니다. 엔드포인트 시크릿으로 「<t>.」+원문 바디에 대한 HMAC을 재계산해 상수 시간으로 비교하고, 불일치는 거부하세요.

Kem-Signature: t=<unix_timestamp>,v1=<hmac_sha256_hex>

signed_input = "<t>." + raw_request_body
v1 = HMAC_SHA256(endpoint_secret, signed_input)   # secret: whsec_...

# reject replays: drop the delivery when |now - t| > 300s
import crypto from "node:crypto";

export function verifyKemSignature(rawBody, header, secret) {
  // header: "t=1720000000,v1=hex"
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = crypto
    .createHmac("sha256", secret)               // secret: whsec_...
    .update(`${parts.t}.`)
    .update(rawBody)                            // the RAW request bytes
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
import hashlib, hmac

def verify_kem_signature(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=") for p in header.split(","))
    expected = hmac.new(
        secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, parts["v1"])

전송과 재시도

2xx로 빠르게 응답하세요. 실패한 전송은 백오프로 재시도된 뒤 데드레터 처리됩니다:

1m · 5m · 30m · 2h · 12h · 24h

테스트

테스트 키로는 돈을 움직이지 않고 결제 전체 흐름을 진행할 수 있습니다 — 전환을 시뮬레이션하고 웹훅이 도착하는 것을 확인하세요:

curl -X POST https://api-business.kemapp.io/v1/payments/{id}/_simulate/succeeded \
  -H "Authorization: Bearer sk_test_..."
BUILT IN THE GULF · SETTLED IN USDT ·
kemBusiness

결제는
스테이블코인으로.

대시보드를 열고 오늘 첫 USDT 결제를 받아 보세요 — 또는 20분 통화로 함께 살펴봐 드립니다.

대시보드 열기↗통화 예약↗

이미 kem을 사용 중이신가요? 로그인

제품

  • 로그인
  • 계정 만들기
  • 데모 예약

모두를 위한 Kem

  • 소비자 앱
  • iOS — App Store
  • Android — Google Play

회사

  • Tether 투자
  • 개인정보 처리방침
  • 이용약관

Kem은 전 세계 사람들에게 금융의 자유를 열어주는 크립토 서비스 생태계입니다.

© 2026 Kem · 본 웹사이트의 콘텐츠는 이를 통해 제공되는 모든 정보, 자료 및 문서를 포함하여 아부다비 글로벌 마켓에 등록된 KEM TECHNOLOGIES HOLDING Ltd(법인번호 000008598)의 기밀 및 독점 자산입니다. KEM TECHNOLOGIES HOLDING Ltd의 사전 서면 동의 없이 이 콘텐츠의 전부 또는 일부를 무단으로 사용, 공개, 배포 또는 복제하는 행위는 엄격히 금지됩니다. [email protected]

걸프에서 제작.