VERIT Anti-Scalping API v1 · Base https://verit.teamplut.com/api/b2b
시작하기 — 샌드박스 키
키는 한 번만 표시됩니다. 샌드박스 키(vk_sandbox_)로 만든 표는 실제 입장에 쓸 수 없고, 나머지 동작은 라이브와 같습니다. 라이브 키(vk_live_)는 도입 계약 뒤 발급합니다.
지금 복사해 두세요. 다시 볼 수 없어요. 시간당 5개까지 발급됩니다.
인증
키는 서버에 해시로만 저장됩니다. 잃어버리면 새로 발급받으세요. 전화번호는 파트너별 HMAC 으로 바뀌어 저장되며 원문은 남지 않습니다.
기본 흐름
리스크 점수 POST/risk/score
예매 버튼을 누른 «한 번의 시도»를 넣으면 0~100 점과 결정을 돌려줍니다. 60 이상 block, 30~59 slow(대기열 뒤로), 그 아래 allow. 점수는 같은 파트너 안에서 축적되는 기록으로 계산되므로 첫 호출부터 의미가 있습니다.
어떤 신호를 어떻게 합치는지는 공개하지 않습니다. reasons 는 운영 참고용 라벨입니다. phone 대신 자체 subject_id 를 보내도 됩니다.
이벤트 · 대기열
/events멱등 등록. ext_event(귀사 ID), title, at, cap_per_person(기본 4).
/queue/token{ext_event, subject_id} → {token, ahead, admitted}. 같은 사람이 다시 부르면 같은 토큰. 앞사람이 없으면 즉시 admitted.
발권
/tickets/issue{ext_event, phone, qty, seats[]}. 같은 사람이 한도(cap_per_person)를 넘기면 403. 응답의 wallet_url 을 관객에게 보내면 끝입니다.
/tickets/{code}/void환불·취소 시 무효화.
동적 QR
/tickets/{code}/code→ {qr, svg, expires_in, step}. 자체 앱에 QR 을 그리려면 expires_in 마다 다시 부르세요. 값은 서버가 만들며 관객 기기 시계를 믿지 않습니다.
입장 검증
/gate/verify{qr} → 200 ok / 409 {reason}. 거부 사유: 없는 표 · 이미 입장함 · 사용할 수 없는 표 · 만료된 코드(캡처) · 다른 파트너의 표. 거부도 전부 기록되어 리포트에 잡힙니다.
정가 양도
/tickets/{code}/rebind{phone, price, face}. price > face 면 403 — 이 한 줄이 암표 제로의 규칙입니다. 통과하면 옛 코드는 transferred 로 죽고 새 코드가 새 사람에게 붙습니다.
증빙 리포트
/events/{ext_event}/report→ 발권·입장·양도·취소 수, 스캔 결과별 집계(ok / 만료 코드 / 중복 …), 리스크 결정별 집계(allow / slow / block). 주최사 정산·보고서에 그대로 씁니다.
v2 · 역방향 입장 (게이트를 관객이 찍는다)
정방향(관객 QR 을 스태프가 스캔) 대신, 입구 화면이 게이트 QR 을 보여 주고 관객 앱이 그걸 찍어 보냅니다. 입장 자격이 그 순간 처음 만들어지므로 공연 전에는 팔 물건이 없습니다. 좌석이 없는 표(구역만 산 표)는 이때 좌석이 정해집니다.
/gate/nonce?ext_event=→ {qr, svg, code, expires_in, step}. 입구 화면(태블릿·TV)이 expires_in 마다 새로 그립니다.
/admit{gate_qr, phone} — 관객 앱이 찍은 게이트 QR 과 관객 계정 번호. → {admitted:[{code, seat, confirm}]}. confirm 4자리가 관객 화면과 스태프 화면에 같이 뜹니다. 지난 코드(캡처)는 409.
공정성 원장
/ledger발권·양도·입장·환매·대기 제안이 해시 체인으로 이어진 기록. 개인정보 없이 해시·좌석·시각만. 누구나 GET https://verit.teamplut.com/api/ledger/verify 로 체인 무결성을 검증합니다. «왜 저 사람이 먼저였나»에 답이 있습니다.
출석 우선권
/priority{phone} → {attendance, tier, suggested_queue_bucket}. 실제 입장(entered) 횟수만 셉니다. 발권·결제는 세지 않습니다. 대기열 앞 구간을 이 값으로 주면, 우선권은 돈으로도 봇으로도 살 수 없게 됩니다.
이 밖에 문서에 적지 않는 비공개 차단 계층이 서버 안에서 항상 함께 돌아갑니다. 파트너 호출에도 같은 계층이 적용됩니다.
Sentinel — 매크로 차단 SDK
파트너 예매 페이지에 스크립트 한 줄을 붙이면, 관객 브라우저가 사람인지 «조용히» 판정한 토큰을 만듭니다. 파트너 서버는 예매 요청에 실린 토큰을 아래 API 로 검증하고 allow / slow / block 을 받습니다. 판정 원리는 공개하지 않으며 SDK 는 «무엇을 재는지»만 담고 있습니다.
/sentinel/verify{token} → {valid, human 0-100, decision allow|slow|block, device}. 토큰은 10분, 기기에 묶여 있습니다.
/sentinel/stats최근 24시간 판정 수·평균·허용·차단.
규모가 큰 오픈은 파트너 센터에서 «Sentinel 강화 모드»를 켜면 그 오픈에만 판정 강도가 올라갑니다.
하드웨어 결속 — 표를 폰 안에
베릿 지갑은 관객 폰의 보안칩(Secure Enclave·StrongBox·TEE)에 키를 만들어 표를 묶습니다. 개인키는 칩 밖으로 나오지 않고, 역방향 입장 요청에는 그 칩의 생체 서명이 실려야 합니다. 파트너가 따로 구현할 것은 없습니다 — 지갑이 처리합니다. 유심 결속은 네이티브 앱에서 아래 어댑터로 더합니다.
/hw/register/options · /hw/registerWebAuthn 플랫폼 인증기 등록(관객 세션). attestation: none, userVerification: required. 등록되면 그 계정의 /admit 은 assertion 필드가 없으면 428 로 거부됩니다.
/hw/assert/options입장 직전 서명 챌린지. 3분 유효, 한 번만 쓰입니다. 서명 카운터가 되돌아가면 복제 키로 보고 표를 격리합니다.
/hw/sim유심 어댑터(네이티브 SDK). {attest:{carrier, sub_hash, device, ts}, sig} — sub_hash 는 앱이 SubscriptionManager(Android)·CoreTelephony(iOS, 통신사 코드까지) 로 얻은 가입자 식별자의 SHA-256, sig 는 SDK 키 HMAC. 원본 ICCID 는 서버에 오지 않습니다. 같은 계정에 다른 유심이 붙는 순간 보유 표가 격리되고 원장에 simchange 가 남습니다.
/hw/keys · /hw/sim이 계정의 결속 상태. 파트너 리포트에는 입장별 hw: true|false 로 집계됩니다.
iOS 는 앱에서도 ICCID 를 읽을 수 없어 유심 결속은 통신사 코드 + 보안칩 키 조합으로, Android 는 가입자 식별자 해시로 묶입니다. 웹 지갑만 쓰는 관객은 보안칩 결속까지 적용됩니다.