고객에게 나갈 답변, 보도자료, 상품 설명, 상담 스크립트 — AI가 쓴 글이든 사람이 쓴 글이든 밖으로 내보내기 전에 베리라인으로 사실 여부를 확인하세요. 응답에는 주장별 판정·근거·출처, 원문 속 위치, 틀린 문장의 고친 문장, 그리고 인용된 법령·판례·문헌이 공식 자료에 없을 때의 부존재 신뢰도가 함께 들어 있습니다.
자사 상품·약관·회사 정보처럼 공개 웹에 없는 사실은 기준 자료(references)로 함께 보내면 그 자료와 먼저 대조합니다.
POST /v1/answer-check. 베리라인 엔진 3.1이 법제처 현행 조문과 코드로 대조하고, 판정 영수증과 책임 범위가 함께 옵니다. 기업 계약의 기본입니다.POST /v1/verify · /v1/documents. 웹 · 공식 레지스트리로 확인하며, 판정 영수증 · 책임 범위는 붙지 않습니다.Authorization: Bearer <API 키> 헤더를 붙입니다.GET /v1/openapi.json — 인증 없이 받을 수 있습니다. Postman·코드 생성기에 그대로 넣으세요.텍스트 하나를 검증합니다. 주장마다 출처 원문을 직접 열어 확인하므로 보통 30~90초가 걸립니다. wait를 주면 결과가 나올 때까지(최대 120초) 연결을 유지하고, 주지 않으면 즉시 202와 id를 돌려주므로 GET /v1/verify/:id로 조회하세요.
| 필드 | 타입 | 설명 |
|---|---|---|
text | string | 검증할 텍스트. 최대 10,000자 |
references | array | 선택. 자사 기준 자료 [{ "title": "요금 안내", "text": "…" }]. 최대 5개, 합계 20,000자. 이 자료가 다루는 주장은 웹보다 먼저 이 자료와 대조해 verified_via: "reference"로 판정하고, 근거 문장을 sources[].quote로 돌려줍니다. 자료에 없는 근거로는 판정하지 않습니다. |
strict | boolean | 선택. 엄격 모드 — 근거를 출처 원문에서 직접 확인한 판정(confidence: "high")만 내립니다(아래 "확신도와 엄격 모드"). |
organization | string | 선택. 자사명. 자사에 관한 주장은 "공개 기록이 없다"는 이유만으로 false가 되지 않습니다(기준 자료가 있으면 그 자료로 판정). |
wait | boolean | number | 선택. true면 최대 120초, 숫자면 그 초만큼 기다림 |
callback_url | string | 선택. 검증이 끝나면(실패 포함) 결과를 이 https 주소로 POST합니다. 폴링이 필요 없습니다. 공인 주소만 가능 |
callback_secret | string | 선택. 주면 웹훅에 서명합니다(아래 "웹훅"). 저장하지 않습니다 |
헤더 Idempotency-Key: <임의 문자열>를 붙이면, 응답을 못 받아 다시 보내도 처음 시작한 검증을 그대로 돌려주고 다시 과금하지 않습니다(24시간). 같은 키로 다른 내용을 보내면 422 idempotency_conflict.
curl -X POST https://veriline.kr/v1/verify \
-H "Authorization: Bearer vl_live_..." \
-H "Content-Type: application/json" \
-d '{"text": "대법원 2019다123456 판결에 따르면 …", "wait": true}'
const res = await fetch("https://veriline.kr/v1/verify", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.VERILINE_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ text, wait: 90 }),
});
let job = await res.json();
while (job.status === "pending") {
await new Promise((r) => setTimeout(r, 3000));
job = await (await fetch(`https://veriline.kr/v1/verify/${job.id}`, { headers: { Authorization: `Bearer ${process.env.VERILINE_API_KEY}` } })).json();
}
import os, time, requests
H = {"Authorization": f"Bearer {os.environ['VERILINE_API_KEY']}"}
job = requests.post("https://veriline.kr/v1/verify", json={"text": text, "wait": 90}, headers=H).json()
while job["status"] == "pending":
time.sleep(3)
job = requests.get(f"https://veriline.kr/v1/verify/{job['id']}", headers=H).json()
{
"id": "9f2c1a7b3d4e5f60",
"status": "done", // pending | done | error
"cached": false,
"created_at": "2026-09-12T03:10:00.000Z",
"completed_at": "2026-09-12T03:10:21.000Z",
"result": {
"verdict": { "label": "부분적으로 부정확", "tone": "false", "detail": "3개 중 1개가 사실과 다릅니다 — …" },
"domain": "법률",
"claims": [
{
"text": "대법원 2019다123456 판결은 …",
"quote": "실제로 대법원 2019다123456 판결도 같은 취지로 판단했습니다.", // 원문 그대로의 해당 부분
"span": { "start": 118, "end": 152 }, // 원문 속 위치(글자 단위, end 제외)
"suggested_fix": "실제로 이 취지의 대법원 판결은 확인되지 않습니다.", // false일 때만
"domain": "법률",
"verdict": "false", // confirmed | false | uncertain
"verified_via": "nec", // official | reference | nec | web | research | unavailable
"explanation": "인용된 ‘2019다123456’은(는) 존재하지 않을 가능성이 높습니다(부존재 신뢰도 0.735). …",
"sources": [],
"legal_ref": { "type": "case", "case_number": "2019다123456" },
"nec": {
"identifier": { "type": "case", "canonical": "2019다123456", "searchSpace": "대법원 판결" },
"score": 0.735, "grade": "nonexistent", "gradeLabel": "부존재 확실", "threshold": 0.7,
"weights": { "w1": 0.65, "w2": 0.2, "w3": 0.15 },
"coverage": { "value": 0.9, "estimated": true, "searched": [ … ] },
"formatError": { "value": 0, "skippedSearch": false, "checks": [] },
"proximity": { "value": 0, "similar": [] },
"uncovered": [],
"summary": "…"
}
}
]
},
"usage": { "used": 12, "quota": 1000, "remaining": 988, "resets_at": "2026-09-30T15:00:00.000Z" }
}
official | 법제처 국가법령정보의 현행 조문·판례·헌재 결정 원문과 대조 |
reference | 요청에 함께 보낸 기준 자료(references)와 대조. 근거 문장이 sources[].quote에 있음 |
nec | 인용된 식별자 또는 사실 주장을 공식 자료·웹에서 찾지 못해 부존재 신뢰도로 판정 |
web | 실시간 웹 자료로 교차 확인 |
research | 앞 단계에서 결론이 나지 않아 도메인별 심층 재확인을 거침 |
unavailable | 외부 자료 조회에 실패해 확인되지 않음 |
AI가 존재하지 않는 판례·법령·논문을 지어내거나, 있지도 않은 통계·사건을 사실처럼 말하는 경우가 있습니다. 데이터베이스에서 "못 찾았다"는 사실만으로 곧바로 "없다"고 단정할 수는 없으므로, 베리라인은 다음 세 지표로 부존재 신뢰도를 산출합니다.
식별자(법령·판례·DOI 등)는 공식 레지스트리가 검색공간입니다. 식별자가 없는 일반 사실 주장은 "이 주장이 사실이라면 어디에 기록되어 있어야 하는가"를 검색공간으로 삼습니다 — 공공 통계·공시처럼 사실이라면 반드시 공표되는 영역을 충분히 탐색하고도 찾지 못하면 부존재 신뢰도가 임계값을 넘어 사실과 다름으로 판정합니다. 반대로 비공개 내부 정보나 개인 경험처럼 애초에 기록이 남지 않는 주장은 탐색 커버리지가 낮아 부존재로 단정하지 않고 확인되지 않음으로 남습니다.
NEC = w1·C + w2·F + w3·(1 − P)
grade가 nonexistent(NEC ≥ 0.7)이면 해당 주장은 false로, unverifiable이면 uncovered에 아직 확인하지 못한 영역과 확인 방법이 담깁니다. 지원 식별자: 판례 사건번호, 헌법재판소 사건번호, 법령·조문, DOI, arXiv, PMID, ISBN.
베리라인이 "사실" 또는 "사실과 다름"이라고 단정한 주장마다 confidence가 붙습니다.
high — 법제처 조문 원문 대조, 보내 주신 기준 자료 대조, 부존재 신뢰도 판정, 또는 근거 문장을 출처 페이지에서 서버가 직접 확인하고 처음 판정을 모르는 독립 검토도 같은 결론을 낸 경우. 이때 evidence: { verified: true, url, quote }가 함께 옵니다.medium — 판정은 있지만 출처 페이지를 직접 열어 확인하지 못한 경우(접속 차단·동적 페이지 등).근거로 제시된 문장이 출처 페이지에 실제로 없거나, 독립 검토가 처음 판정과 다르게 보면 판정을 내리지 않고 uncertain으로 둡니다. 요청에 "strict": true를 주면 엄격 모드로, high만 판정하고 나머지는 모두 uncertain입니다 — 베리라인이 단정하는 말은 원문으로 확인된 것뿐이어야 하는 곳(광고 심의·공시·법무 검토)에 쓰세요.
"없다"고 말하는 주장도 검증합니다. "그런 판례는 존재하지 않는다", "민법에는 제750조가 없다"처럼 대상의 존재를 부정하는 주장에는 absence_of(없다고 한 대상)가 붙고, 판정은 그 방향 기준입니다 — 없는 것을 없다고 했으면 confirmed, 실재하는 것을 없다고 했으면 false(실재 출처 첨부). 검색에 나오지 않는다는 것만으로는 "없다"를 확인하지 않고, 기록이 있어야 할 공간을 충분히 확인했을 때만(부존재 신뢰도) 판정합니다.
uncertain인 주장에는 이유를 알려 주는 uncertain_reason이 붙습니다.
no_evidence — 근거 없음. 공개된 자료 어디에서도 근거를 찾지 못했습니다. 근거 없이 단정한 내용이니 사실로 쓰면 안 됩니다. (공개 기록이 반드시 있어야 하는 종류인데 없으면 이 단계가 아니라 false로 판정합니다.)not_public — 공개 기록 밖. 유료 평점·개인 경험·비공개 내부 정보처럼 사실이어도 공개 웹에 없을 수 있는 종류라, 없다는 사실만으로 틀렸다고 하지 않습니다.check_failed — 조회 실패. 일시적 오류로 확인을 끝내지 못했습니다. 다시 요청해 주세요.quote·span — 그 주장이 나온 원문 부분과 위치입니다. text.slice(span.start, span.end)가 quote와 같습니다. 원문에서 정확히 찾지 못한 주장에는 붙지 않습니다.suggested_fix — 판정이 false일 때만, 판정 근거에 적힌 실제 값으로 그 부분을 고친 문장입니다. 근거에 실제 값이 없으면 붙지 않습니다. 원문의 문체는 그대로 두고 틀린 부분만 바꿉니다. 바꿀 실제 대상이 없는 인용(존재하지 않는 판례 등)은 인용만 지우지 않고 "확인되지 않는다"는 문장으로 바꿉니다.counter_fact — 판정이 false일 때, 다시 확인해서 찾은 실제 값입니다(예: "8,848.86m(2020년 네팔·중국 공동측량)").여러 건을 한 번에 보냅니다(최대 20건). references·organization은 묶음 전체에 적용됩니다. 남은 한도가 항목 수보다 적으면 한 건도 시작하지 않고 429를 돌려줍니다 — 일부만 처리되어 무엇이 빠졌는지 맞춰 보는 일이 없게 하려는 것입니다.
{ "items": [ { "ref": "faq-01", "text": "…" }, { "ref": "faq-02", "text": "…" } ],
"references": [ { "title": "상품 설명서", "text": "…" } ], "wait": 60 }
→ { "count": 2, "pending": 0, "results": [ { "ref": "faq-01", "id": "…", "status": "done", "result": { … } }, … ] }
챗봇·상담 AI가 쓴 답을 사용자에게 보내기 전에 넣으면, 확인을 거친 답 그 자체(text)를 돌려줍니다. 법령은 법제처 현행 조문 전체와 대조하고 반론 검토를 통과한 오류만 고칩니다. 그 밖의 사실(의료·의약, 경제·금융, 세금, 노동, 부동산, 기업, 복지·행정, 통계)은 그 분야의 한국 공식 기관 사이트에서 먼저 확인하고, 결론이 안 나면 웹 전체로 넓힙니다. 틀린 곳은 근거대로, 확인되지 않은 곳은 단정하지 않게 고칩니다. 보통 10~60초, 답 1,000자마다 1건, 확인을 끝내지 못하면 과금하지 않습니다.
{ "question": "임금을 안 주면 사장님은 어떤 처벌을 받나요?", "answer": "3년 이하의 징역 또는 3천만원 이하의 벌금…", "level": "fast" }
→ { "text": "5년 이하의 징역 또는 5천만원 이하의 벌금…(근거: 근로기준법 제107조)", "changed": true,
"verification": {
"engine": "veriline-3.1", // 판정한 엔진. "veriline-1"이면 예전 길로 확인했고 영수증 · 책임 범위가 없습니다
"fixes": [ { "quote": "…3년 이하의 징역 또는 3천만원…", "problem": "현행 제107조 제1항은 5년 · 5천만원", "official": true, "field": "labor" } ],
"receipts": [ { "id": "c1", "verdict": "false", "decided_by": "code", // code | model_locked(원문 인용으로 잠근 모델)
"source": { "law": "근로기준법", "article": "제107조", "effective": "…", "url": "…", "text_sha256": "…", "fetched_at": "…" } } ],
"guarantee": { "status": "covered", "covered": [ … ], "uncovered": [ … ] }, // covered | partial | not_covered — 이용 조건 제10조의2
"hedged": [], "supported": [ … ], "articles": [ … ] }, "billed_units": 1 }
판정 영수증(receipts)은 판정마다 누가(코드 / 원문 인용으로 잠근 모델) 어느 조문 · 시행일 · 원문 지문으로 정했는지 적은 기록입니다. 영수증을 POST https://veriline.kr/api/receipts/replay에 보내면 모델 호출 없이 같은 판정이 다시 계산됩니다. 책임 범위(guarantee)에 든 판정만 이용 조건 제10조의2(환불 + 정정 보고서)의 대상입니다.
level: fast(가벼운 답) · standard · deep(중요한 답) — 답을 쓴 모델 등급에 맞춥니다. 답을 쓰기 전에 POST /v1/context { "question" }를 부르면 관련 현행 조문을 block으로 받아 모델 안내에 넣을 수 있습니다(과금 없음). "facts": true를 주면 베리라인이 공식 출처로 확인해 둔 관련 사실(공식 원문 인용 · 링크)도 함께 옵니다 — 다른 고객이 보낸 글의 문장은 들어 있지 않습니다.
1만 자를 넘는 문서나 파일(DOCX·HWPX·PDF·TXT·MD·CSV, 10MB까지)을 그대로 보냅니다. 베리라인이 문단 경계로 나눠 검사하고, 결과를 원문 전체 기준 위치로 합쳐 돌려줍니다. 틀린 문장을 고친 문장으로 바꾼 corrected_text(고친 본문)도 함께 줍니다.
text(최대 100,000자) 또는 file: { "name": "보도자료.hwpx", "content_base64": "…" }. title·references·organization·callback_url·wait·Idempotency-Key는 단건과 같습니다.429, needed·remaining 포함).document.completed입니다(원문 text는 빼고 보냅니다).{ "id": "doc_3f…", "object": "document", "status": "done", // pending | done | partial | error
"parts": { "total": 3, "done": 3, "failed": 0 },
"result": {
"verdict": { "label": "부분적으로 부정확", … },
"counts": { "claims": 18, "false": 2, "uncertain": 3, "confirmed": 13 },
"claims": [ { "quote": "…", "span": { "start": 10432, "end": 10471 }, "verdict": "false", "suggested_fix": "…", … } ],
"corrected_text": "…고친 문장이 반영된 전체 본문…", "fixes_applied": 2 },
"text": "…원문…" }
GET /v1/documents/:id로 진행 상황과 결과를 조회합니다(같은 계정의 키로 만든 문서만).
문서 검사에서 모든 사실 주장이 출처 원문으로 확인(confidence: "high")되면 검증 마크를 발급할 수 있습니다. 마크를 받으면 글과 주장별 근거가 공개 검증 페이지에 실리므로 publish: true(공개 동의)가 필요합니다.
POST /v1/documents/:id/mark
{ "publish": true }
→ 201
{ "id": "ym…", "object": "mark", "status": "valid",
"url": "https://veriline.kr/v/ym…", // 공개 검증 페이지
"certificate_url": "https://veriline.kr/v/ym…/certificate", // A4 검증서(PDF)
"badge_url": "https://veriline.kr/v/ym…/badge.svg",
"embed_html": "<div data-yume-mark=\"ym…\">…</div><script src=\"…/v/embed.js\" async></script>",
"text_hash": "…", "issued_at": "…", "expires_at": "…" }
422 not_eligible과 함께 blockers(주장별 이유)를 돌려줍니다.200, renewed: true). 이미 붙여 둔 삽입 코드가 그대로 살아 있습니다.status: "expired"(재확인 필요)가 됩니다. POST /v1/marks/:id/revoke로 철회할 수 있습니다.embed_html은 검증받은 글을 감싸는 요소와 스크립트입니다. 감싼 글의 글자를 원문 지문(공백을 뺀 SHA-256)과 대조해, 글이 바뀌면 마크가 "원문 변경됨"으로 표시됩니다.GET /v/:id/status.json으로 상태를 조회할 수 있습니다(인증 없음, CORS 허용).callback_url을 주면 검증이 끝날 때 아래처럼 보냅니다. 묶음 요청은 항목마다 ref를 붙여 하나씩 보냅니다. 2xx를 받지 못하면 최대 4번까지 다시 보냅니다(0초·2초·10초·60초).
POST https://고객사/veriline-hook
X-Veriline-Event: verification.completed
X-Veriline-Delivery: 3f9a… // 같은 전달의 재시도는 같은 값
X-Veriline-Timestamp: 1791234567
X-Veriline-Signature: sha256=… // callback_secret을 줬을 때만
{ "event": "verification.completed", "ref": "faq-01", "id": "…", "status": "done", "result": { … } }
서명 확인: hmac_sha256(callback_secret, X-Veriline-Timestamp + "." + 원문 본문)의 hex가 sha256= 뒤 값과 같은지 보세요. 시각이 5분 넘게 차이 나면 버리세요(재전송 방지).
// Node.js
const sig = "sha256=" + crypto.createHmac("sha256", SECRET).update(req.headers["x-veriline-timestamp"] + "." + rawBody).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(req.headers["x-veriline-signature"]));
같은 계정의 키로 요청한 검증만 조회할 수 있습니다. 조회는 과금되지 않습니다.
{ "key": { "label": "운영 서버", "prefix": "vl_live_ab12cd…" }, "rate_per_min": 30,
"month": { "used": 12, "quota": 1000, "remaining": 988, "resets_at": "…" } }
POST /v1/verify 1건입니다(같은 텍스트의 캐시 재사용 포함). 입력 오류·인증 실패·한도 초과로 거절된 요청은 과금되지 않습니다.429와 Retry-After 헤더를 돌려줍니다.{ "error": { "code": "quota_exceeded", "message": "…" } }
| HTTP | code | 의미 |
|---|---|---|
| 400 | invalid_request | text가 비어 있음 |
| 400 | invalid_references | 기준 자료 형식이 틀림(개수·길이·text 누락) |
| 400 | invalid_callback / invalid_idempotency_key | 웹훅 주소(https 공인 주소만) 또는 멱등 키 형식이 틀림 |
| 409 | idempotency_in_progress | 같은 키의 첫 요청을 아직 시작하는 중 |
| 422 | idempotency_conflict | 같은 키로 다른 내용을 보냄 |
| 401 | invalid_api_key | 키가 없거나 폐기됨 |
| 404 | not_found | 검증 id가 없거나 다른 계정의 것 |
| 413 | text_too_long | 10,000자 초과 |
| 429 | rate_limited / quota_exceeded | 분당 한도 / 월 한도 초과 |
기준 자료(references)는 저장하지 않습니다. 검증 한 건을 처리하는 동안만 쓰고, 그 자료로 낸 판정은 다른 고객에게 재사용되는 캐시에 넣지 않습니다.
API로 보낸 텍스트는 검증과 과금·분쟁 대응을 위해 1년간 보관되며, 별도 계약으로 허용한 경우를 제외하고 데이터셋 제공 대상에 포함되지 않습니다. 텍스트에 개인정보가 들어간다면 귀사 이용자에게 필요한 고지·동의를 받아주세요. 자세한 내용은 개인정보처리방침과 이용약관을 참고하세요.