메인 콘텐츠로 건너뛰기

Trace Provider 데이터 감사 — 통합 및 API 레퍼런스

Trace 데이터 감사 API의 단일 정보 출처(single source of truth): provider 온보딩, 인증, Trace Schema, 쓰기 및 읽기 엔드포인트, 검색, 통계, scoped 그룹, 제한, 그리고 검증에 관한 문서입니다.
이 API와 Trace Schema는 provider에 구애받지 않습니다(provider-agnostic) — 모든 provider는 동일한 엔드포인트, 헤더, 스키마를 통해 통합됩니다. 예제에서는 실제 운영 중인 provider인 Kled를 사용합니다. Kled가 등장하는 모든 곳을 본인 provider의 식별 정보로 대체하시면 됩니다.

환경(Environments)

Staging은 새로운 provider 통합을 온보딩하고 테스트하는 환경입니다. Production은 배포되어 있지만 아직 provider 데이터가 없을 수 있습니다 — 프로덕션 트래픽을 보내기 전에 DATA Foundation 팀에 확인하십시오.

접근 권한 얻기

쓰기 접근은 게이팅되어 있습니다. 통합 전에 DATA Foundation 팀에 연락해 온보딩을 받으십시오. 저희가 provider 식별 정보를 화이트리스트에 등록하고, 스테이징 및 프로덕션 API 키를 발급하며, 쓰기 요청에 사용해야 하는 X-Provider 값을 할당합니다. 이 과정이 완료되기 전까지는 쓰기 요청이 거부됩니다. 읽기, 검색, scoped 그룹 엔드포인트는 공개된 감사 뷰이므로 키가 필요하지 않습니다.

인증 및 provider 범위

모든 쓰기 요청에는 다음 헤더가 포함되어야 합니다:
  • API 키는 본인 provider에 속해야 하고 X-Provider와 일치해야 합니다. 대상 환경에 해당하는 키를 사용하십시오.
  • 백로그(backlog) 적재의 경우 X-Ingestion-Source: backlog를 추가하십시오. 라이브 적재의 경우 헤더를 생략하십시오 — 명시적인 live 값은 허용되지 않습니다.
  • 읽기 API는 전역 data_id로 키가 지정됩니다. provider는 필드로 반환되며 선택적 필터로도 사용됩니다.
읽기, 검색, scoped 그룹 엔드포인트는 공개 감사 뷰입니다. 엔터프라이즈 전용이거나 민감한 필드를 공개 Trace 페이로드에 넣지 마십시오. provider 전용 또는 파트너 전용 읽기 계층이 필요해질 경우, 이는 별도의 API/제품 결정 사항입니다.

적재(Ingestion) 흐름

1

배치 전송

provider 클라이언트가 webhook 배치 엔드포인트로 POST 요청을 보냅니다.
2

비동기 처리

수락된 항목은 큐에 적재되어 DATA Foundation에서 비동기적으로 처리됩니다.
3

다시 읽기

레코드는 읽기 및 검색 엔드포인트를 통해 조회할 수 있게 됩니다.
records:batch 응답에는 항상 항목별 상태가 포함됩니다:
  • 202 Accepted — 최소 하나의 항목이 비동기 처리를 위해 수락되었고 충돌한 항목이 없습니다.
  • 200 OK — 모든 항목이 중복이어서 새로운 비동기 작업이 큐에 등록되지 않았습니다.
  • 409 Conflict — 최소 하나의 항목에서 충돌이 발생했습니다. 같은 응답에 포함된 accepted 항목은 정상적으로 큐에 등록됩니다.
각 항목의 상태를 확인하고, 일시적인 요청 실패는 동일한 페이로드와 동일한 X-Batch-Id로 재시도하십시오.

레코드 라이프사이클

각 레코드의 이력은 append-only 이벤트 로그이며, Trace는 이를 타임라인으로 렌더링합니다. 각 단계는 정확히 하나의 값에 매핑되며, 해당 값이 존재하는 시점에 단계가 타임라인에 나타납니다. 1–3단계는 등록 페이로드의 메타데이터에서 옵니다. 4–7단계는 감사 이벤트입니다. 각 마일스톤을 별도의 메타데이터 업데이트로 전송하십시오 — 하나의 마일스톤당 하나의 타임라인 이벤트입니다. occurred_at은 두 위치에 존재하며 모두 provider가 제공합니다: 각 배치 항목의 루트 필드가 필수이며 이벤트의 날짜/시각을 지정합니다. timestamps.occurred_at은 attested 페이로드 내부에서 동일한 시점을 담습니다 — 이 둘은 동일하게 유지하십시오. DATA Foundation이 추가하는 값은 ingested_at과 tx_hash뿐입니다.

Trace Schema v1.0

표준화된 Trace Schema 필드를 직접 채우고, 원본 공개 페이로드 전체는 provider_payload 아래에 보존하십시오. 정규화된 필드는 프런트엔드와 감사 흐름이 사용하는 이식 가능한 계약이며, provider 고유 정보는 어떤 것도 손실되지 않습니다.
  • initial_metadata_json 및 metadata_json에서 schema_version: trace-v1.0을 사용하십시오. 값 자체는 검증되지 않으며 — schema_version이 누락되었거나 파싱 불가능한 경우 trace-v1.0으로 기본 처리되고, 어떤 값이 전송되든 이벤트 해시 계산에 반영됩니다.
  • DATA Foundation은 내부 이벤트 해시 계산 전에 메타데이터 JSON을 canonicalize하므로 객체 키 순서는 idempotency나 충돌 감지에 영향을 주지 않습니다.
  • 쓰기 페이로드에 트랜잭션 해시를 보내지 마십시오. tx_hash는 DATA Foundation이 소유하며, 등록, 메타데이터 업데이트, 검색 결과 행에 대한 읽기 응답에 반환됩니다 — 브로드캐스트 후 DATA Foundation이 채우기 전까지는 빈 문자열입니다.

Canonical content hash (필수)

초기 등록 및 메타데이터 업데이트에는 하나의 canonical content hash가 포함되어야 합니다. 허용되는 필드는 asset.hash, content_hash, file.content_sha256, file.hashes.sha256이며, 모두 sha256:<64-lowercase-hex> 형태로 정규화됩니다. 두 개 이상의 alias가 존재하는 경우 동일한 해시를 나타내야 합니다.

권장 최상위 형태

검색 가능 필드(Searchable fields)

현재 exact-match 검색이 가능한 필드입니다: 검색 가능한 해시는 canonical content SHA-256뿐입니다 — perceptual 해시(phash64, dhash64, ahash64, keyframe_phashes) 및 md5는 저장은 되지만 인덱싱되지 않습니다. app.platform_name, app.legal_entity, file.behavior.*, file_specific.base.motion.*, timestamps.payment_credited_at도 동일합니다: 유용할 때 보내십시오 — 저장된 필드는 이전 데이터를 다시 보내지 않고도 추후 인덱싱이 가능합니다. 분포는 /stats를 사용하고, provider는 선택적 쿼리 범위로 사용하십시오.

필드 가이드

  • source_record_id — provider가 소유하는 안정적인 공개 미디어 ID(예: kmf_...). 서비스는 주변 공백을 제거하고, 대소문자를 유지하며, 제어 문자는 거부하고, 최대 512바이트까지 허용합니다.
  • contributor.anon_id — provider가 소유하는 공개 익명화 기여자 ID.
  • contributor.kyc_status — 권장 값: verified, pending, failed, unverified.
  • contributor.kyc_country — 가능한 경우 KYC에서 얻은 ISO 3166-1 alpha-2 국가 코드. 국가 코드만 사용하며, 주소나 GPS 기반 국가는 포함하지 않습니다.
  • contributor.tax_status — 권장 값: submitted, not_submitted, not_applicable, unknown. tax_form_on_file 같은 boolean은 true를 submitted로, false를 not_submitted로 매핑하십시오.
  • contributor.account_verification_status — 권장 값: verified, pending, failed, unverified.
  • contributor.consent.tos_* 및 contributor.consent.privacy_policy_* — 이 레코드에 대해 기여자가 동의한 정확한 정책 버전, 해시, URI. provider 수준의 활성 정책은 레코드 페이로드 내부가 아니라 PUT /webhook/v1/data-audit/provider-policy를 통해 별도로 설정합니다.
  • attestation — 스테이징에서는 서명이 선택 사항입니다. 프로덕션 검증에는 payload_hash, signature, key_id, key_url, signed_at_utc를 함께 전송하십시오.
  • app.legal_entity — 앱/플랫폼 이름과 함께 법적 상대방 정보.
  • file.behavior — 비-PII 캡처/업로드 행동 신호.
  • file_specific.base.motion — 미디어 타입 전반에 걸쳐 공유되는 모션 신호.
  • timestamps.payment_credited_at — provider가 기여자에 대한 지급을 최종 확정하고 정산한 시점의 선택적 UTC 타임스탬프. 정산되지 않은 경우(또는 지급이 몰수된 경우) 생략하십시오. 등록 이후에 지급이 이루어진 경우 전체 상태(full-state) 메타데이터 업데이트로 전송하십시오. 저장 전용(stored-only) 필드입니다.
영속 행과 인덱스 행에 함께 저장됩니다. 향후 변경 사항은 이력을 그 자리에서 변경하기보다는 전환 기간 동안 dual-write/dual-read 방식을 사용해야 합니다.

쓰기 API

활성 provider 정책 설정

provider가 새로운 이용 약관(Terms of Service) 또는 개인정보 처리방침(Privacy Policy)을 게시할 때 이 엔드포인트를 사용하십시오. Trace는 활성 버전, 해시, URI를 저장하여 프런트엔드가 정책에 링크할 수 있게 하고, stats가 레코드를 정책과 비교할 수 있게 합니다.
정책 행은 감사 전용입니다 — 인덱싱되거나 집계되지 않습니다. 레코드 페이로드는 여전히 contributor.consent.*를 담고 있으며, /stats, scoped 그룹 요약, 그리고 policy-hash 검색이 사용하는 것은 이 레코드 수준의 참조입니다.
tos와 privacy_policy 객체는 모두 필수이며, 각각 version, hash, uri를 포함해야 합니다. effective_at은 선택 사항입니다. 해시는 asset 해시와 동일한 형식(sha256:<64-hex>, bare hex, 0x<64-hex>, 0x1220<64-hex>)을 받아들이며, canonical하게 sha256:<64-lowercase-hex> 형태로 저장됩니다. 요청 본문은 1 MiB로 제한됩니다. 현재 및 과거 정책 문서를 읽는 방법:

레코드 등록

초기 백로그 및 라이브 등록 배치에 이 엔드포인트를 사용하십시오. provider는 안정적인 source_record_id를 보내고, DATA Foundation이 data_id를 생성하여 매핑을 반환합니다.
요청 본문은 JSON 배열입니다. initial_metadata_json은 위의 권장 최상위 형태를 따릅니다(여기서는 축약됨):
initial_metadata_root는 canonical Trace Schema v1.0 메타데이터 JSON에 대한 provider의 결정적(deterministic) 0이 아닌 해시여야 합니다. DATA Foundation은 이 값을 제출된 그대로 저장하며, initial_metadata_json에 대한 해시 검증은 아직 강제되지 않습니다. 성공 응답(신규 항목이 큐에 등록된 경우 202, 모든 항목이 중복인 경우 200, 항목 중 하나라도 충돌한 경우 409):
반환된 data_id는 이후의 메타데이터 업데이트와 읽기에 사용되는 canonical ID입니다. 동일한 X-Provider + source_record_id를 다시 보내면 동일한 data_id가 생성됩니다. 항목별 상태: 정확히 동일한 페이로드로 이미 저장된 항목은 duplicate를 반환합니다. 동일한 source_record_id이지만 다른 초기 메타데이터를 가진 항목은 conflict를 반환합니다. 이 둘 모두 (재)큐잉되지 않으며, 배치 내의 다른 유효한 항목은 영향을 받지 않습니다. 첫 번째 요청이 여전히 큐에 있는 동안 겹치는 재시도가 들어오면 accepted를 반환할 수도 있습니다 — 다운스트림 적재는 여전히 idempotent합니다. 호출자가 이미 DATA Foundation이 할당한 UUID를 보유하고 있는 경우, 더 낮은 수준의 POST /webhook/v1/data-audit/data-ids:batch 엔드포인트가 존재합니다. 이 엔드포인트는 모든 레코드에 data_id가 필요하며, 권장되는 provider 경로는 아닙니다.

메타데이터 업데이트 제출

이후의 수정이나 변경 가능한 메타데이터 변경에 이 엔드포인트를 사용하십시오. seq는 data_id별로 1–100 범위여야 합니다(모든 환경에서 레코드당 업데이트 하드 캡 100회). 동일한 provider 측 리비전에 속하는 변경 사항은 하나의 업데이트와 하나의 seq를 공유할 수 있습니다.
metadata_json은 canonical content hash를 포함해야 하며 최신 Trace 메타데이터의 전체 상태(full latest Trace metadata state) 여야 합니다 — diff나 patch가 아닙니다. KYC만 변경되었더라도 변경되지 않은 file, app, consent, provider payload 필드까지 모두 포함하여 각 이벤트가 metadata_root에 대해 검증되고 병합 규칙 없이 최신 상태를 재구성할 수 있도록 하십시오.
요청 본문은 JSON 배열입니다:
metadata_root는 canonical한 업데이트된 전체 Trace Schema v1.0 메타데이터 JSON에 대한 provider의 결정적 0이 아닌 해시여야 합니다. prev_metadata_root 또한 0이 아닌 루트여야 합니다. DATA Foundation은 이 값들을 제출된 그대로 저장하며, metadata_json에 대한 해시 검증은 아직 강제되지 않습니다.
일반적인 통합 경로는 /records:batch의 application/json입니다 — 이 라우트는 JSON만 허용합니다. 백로그 도구를 위해 다음과 같은 더 낮은 수준의 라우트 변형도 존재합니다. 데이터 ID 파일 라우트는 모든 레코드에 data_id가 필요합니다.
  • NDJSON은 Content-Type: application/x-ndjson과 Content-Encoding: gzip을 요구합니다. 압축 해제된 각 줄은 JSON 엔드포인트와 동일한 필드를 가진 하나의 JSON 레코드입니다.
  • CSV는 Content-Type: text/csv를 요구합니다.
    • 데이터 ID 컬럼: data_id,source_record_id,initial_metadata_root,initial_metadata_json,occurred_at
    • 메타데이터 업데이트 컬럼: data_id,seq,prev_metadata_root,metadata_root,metadata_json,occurred_at
    • initial_metadata_json과 metadata_json은 따옴표로 감싼 CSV 필드 안에 유효한 JSON이어야 하며 하나의 canonical content hash를 포함해야 합니다.
  • TXT는 Content-Type: text/plain을 요구하며, 라인 구분 JSON, JSON 배열, 또는 동일한 CSV 컬럼을 사용하는 헤더 구분 쉼표/탭 텍스트를 받아들입니다.

읽기 API

읽기 엔드포인트는 공개 감사 뷰입니다. provider는 선택 사항이며 범위를 좁히는 필터로 작동합니다. 읽기 모델:
  • GET /data-ids/{data_id}는 등록 프로필과 최신 원시(raw) 메타데이터 이벤트를 반환합니다 — 저장된 최상위 시퀀스의 정확한 페이로드이며, 반드시 diff는 아닙니다.
  • GET /data-ids/{data_id}/metadatas는 seq: 0의 등록과 이후의 메타데이터 업데이트를 포함하는 전체 append-only 메타데이터 이력을 반환합니다.
  • 검색, 자산 영수증 조회, scoped 그룹 요약은 DATA Foundation이 해당 이벤트에서 도출한 정규화된 최신 상태 프로젝션을 사용합니다. 이 프로젝션은 MIME 타입, 미디어 카테고리, KYC 상태, TOS/privacy 버전, 라이프사이클 상태, tx_hash와 같은 필드를 제공합니다.

data ID로 trace 조회

메타데이터 이력 나열

각 메타데이터 행은 tx_hash를 포함하며, 초기값은 빈 문자열입니다:

인덱싱된 필드로 검색

검색은 검색 가능 필드에서 exact-match로 수행됩니다. source_record_id 검색은 exact이며 대소문자를 구분합니다. 각 매치에는 tx_hash(초기값은 빈 문자열)가 포함되며, 응답에는 페이지네이션을 위한 next_cursor가 포함됩니다. limit은 기본 100이며 1000으로 상한이 설정되어 있습니다 — 그보다 큰 값은 거부되지 않고 조용히 클램프됩니다. 일반적인 흐름: 정확한 필드 값으로 레코드를 찾을 때는 /search를 사용하고, 감사 검증에 사용되는 canonical 이벤트 페이로드를 위해서는 /data-ids/{data_id} 또는 /data-ids/{data_id}/metadatas를 사용하십시오. 분포 카운트는 /stats를 사용하고, UI에 최신 레코드가 필요한 경우 /recent 또는 /feed를 사용하십시오. 더 많은 예시:

provider 집계(/stats)

레코드 총계는 등록된 각 레코드를 한 번씩 카운트합니다. 기여자 총계는 서로 다른 provider + contributor_anon_id 값을 카운트합니다. 메타데이터 업데이트는 이 둘을 변경하지 않지만, 분포와 크기 총계는 최신 프로젝션을 따르므로 전체 상태(full-state) 업데이트로 레코드가 버킷 사이에서 이동할 수 있습니다. average_size_bytes는 양의 크기를 가진 레코드만 카운트하여 total_size_bytes / size_record_count로 계산됩니다. shard_count는 예약되어 있으며(현재 0), provider_* 필드는 ?provider=와 함께만 나타나고, active_*는 해당 provider가 활성 정책을 가지고 있을 때만 나타납니다. 앱/플랫폼 필드는 stats 범위가 아닙니다.

최근 적재 피드

피드는 최근 감사 이벤트 — 등록 및 메타데이터 업데이트 모두 — 를 적재 시간 기준으로 최신 순으로 반환합니다. 행에는 event_type, seq, data_id, source_record_id, asset_hash, occurred_at, ingested_at이 포함됩니다. 더 오래된 행을 가져오려면 next_cursor를 사용하십시오.

최근 등록된 레코드

등록된 receipt 행만 적재 시간 기준으로 최신 순으로 반환합니다. 더 오래된 행을 가져오려면 next_cursor를 사용하십시오.

content hash로 자산 receipt 조회

허용되는 해시 형식은 sha256:<64-hex>, plain <64-hex>, 0x<64-hex>, 0x1220<64-hex>입니다. 응답은 canonical한 sha256:<64-lowercase-hex> 자산 해시와 매치된 모든 receipt 행을 반환합니다.

Scoped groups

scoped 그룹은 Trace 프런트엔드나 파트너 리뷰어가 리뷰 세트에 대한 공개 스냅샷을 생성할 수 있게 해줍니다. provider 리뷰 워크플로우에서는 랩(lab)이 provider의 source_record_id 값을 제출해야 합니다. Trace는 결정적인 data_id를 계산하고 모든 레코드의 존재 여부를 검증한 뒤, 전체 세트가 유효한 경우에만 그룹을 생성합니다. (hashes / hashes_text를 통해 content 해시로부터 그룹을 생성할 수도 있으며, 두 입력 방식은 상호 배타적입니다.) 생성은 비동기적으로 이루어지므로, GET /scoped-groups/{group_id}를 폴링하여 status가 complete가 될 때까지 대기하십시오.

그룹 생성

source-record 그룹은 all-or-nothing 방식입니다:

더 큰 리뷰 세트를 위한 업로드

더 큰 source-record CSV/TXT 입력의 경우 먼저 presigned 업로드 URL을 요청하십시오:
지원되는 형식은 csv와 txt입니다. 반환된 Content-Type 헤더로 반환된 upload_url에 파일 바이트를 업로드한 뒤, 반환된 upload_id로 그룹을 생성하십시오.
업로드된 CSV에 provider 컬럼이 있는 경우에만 create 요청에서 provider를 생략하십시오.

그룹 읽기

GET /scoped-groups/{group_id}는 그룹 상태를 반환하며, 완료되면 summary에 집계 메트릭이 포함됩니다. profile.status는 pending, processing, complete, failed 중 하나입니다. summary는 그룹이 complete 상태일 때만 나타납니다.
/items는 제출된 각 source_record_id에 대해 확인된 data_id, asset_hash, receipt 요약과 함께 하나의 행을 반환합니다. cursor 기반 페이지네이션을 사용하며, 더 많은 행이 있는 경우 next_cursor를 반환합니다. /items와 /export.csv 모두 그룹이 complete 상태여야 하며, 그 전에는 409를 반환합니다. source-record 그룹의 경우 CSV export 컬럼은 input_type,provider,source_record_id,data_id,asset_hash,status,mime_type,media_category,kyc_status,tos_version,privacy_policy_version,tx_hash이며, hash-manifest 그룹은 대신 hash,status,data_id,...로 시작합니다.

제한 및 재시도 동작

재시도 가이드:
  • 502, 503, 504, 네트워크 타임아웃, 429는 지수 백오프와 지터를 사용해 재시도하십시오. (공개된 scoped-group create/upload 엔드포인트만 429를 반환하며 — IP당 분당 60 요청 — webhook 배치 엔드포인트는 결코 반환하지 않습니다.)
  • 검증/인증 관련 4xx는 요청을 수정하기 전까지 재시도하지 마십시오.
  • 재시도 시 data_id, 요청 본문, X-Batch-Id를 안정적으로 유지하십시오.
  • X-Ingestion-Source: backlog는 백로그 작업에만 사용하십시오. 라이브 작업에서는 생략하십시오.
  • 쓰기 경로는 동일한 data_id, 이벤트 키, 이벤트 해시에 대해 idempotent합니다.
  • 동일한 data_id와 이벤트 키가 다른 메타데이터로 재시도되면 해당 레코드는 충돌로 처리되어 거부됩니다.

검증 규칙

전달 시맨틱(Delivery semantics)

  • 전달은 최소 1회(at least once)이므로 중복 제출이 발생할 수 있습니다.
  • 동일한 이벤트의 중복 제출은 idempotent하게 처리됩니다.
  • 동일한 data_id, 동일한 메타데이터 시퀀스, 서로 다른 이벤트 내용은 충돌로 처리됩니다.
  • 메타데이터 업데이트가 초기 data ID 등록 이전에 도착할 수 있습니다.
  • 감사 데이터는 영속적이며 만료되지 않습니다.
  • 이벤트 해시는 canonicalize된 메타데이터 JSON과 event/hash/schema 버전 필드로부터 계산됩니다.