Trace
TraceIntegration guide

Integration guide · v1 · staging-api.storyprotocol.net

Send a webhook. That's the integration.

Trace stores a provider-normalized Trace Schema v1.0 record per asset. The contributing app POSTs batches of registrations and metadata updates; Trace handles indexing, search, and onchain registration on the app's behalf.

Base URL · https://staging-api.storyprotocol.net

Headers

Auth & provider scope

Every write request must include three headers. The API key must be bound to the provider sent in X-Provider.

X-API-Key: <Kled staging key>
X-Provider: kled
X-Batch-Id: <stable batch id>

Read endpoints accept the same API key; authorization is not provider-scoped. provider can be sent as an optional filter on the search endpoint.

Write API

Register initial data IDs

Use this for initial backlog and live registration batches. The request body is a JSON array of records.

POST /webhook/v1/data-audit/data-ids:batch
Content-Type: application/json
X-API-Key: <Kled staging key>
X-Provider: kled
X-Batch-Id: kled-dataids-000001
[
  {
    "data_id": "11111111-1111-4111-8111-111111111111",
    "source_record_id": "kmf_8a9c2e7d4b1f0e23",
    "initial_metadata_root": "sha256:<canonical-trace-schema-v1-json>",
    "initial_metadata_json": {
      "schema_version": "trace-v1.0",
      "file": {
        "content_sha256": "b1946ac92492d2347c6235b4d2611184",
        "mime_type": "video/mp4",
        "media_category": "video",
        "size_bytes": 123456,
        "hashes": {
          "phash64": "facebeef01234567",
          "dhash64": "1b9072d44a8be3c1",
          "ahash64": "ff7e3c1a90d5e8c2",
          "keyframe_phashes": ["0011223344556677"]
        },
        "behavior": {
          "captured_via": "ios_native_camera",
          "uploaded_via": "ios_app",
          "upload_session_kind": "gallery_pick"
        }
      },
      "file_specific": {
        "base": { "motion": { "speed_bucket": "stationary" } },
        "video": { "duration_ms": 120000, "width": 1920, "height": 1080 }
      },
      "user": {
        "source_user_id": "kup_123",
        "kyc_status": "verified",
        "kyc_country": "US",
        "tos_accepted": {
          "version": "2026-05-20",
          "accepted_at": "2026-05-13T00:00:00Z"
        },
        "privacy_policy_accepted": {
          "version": "2026-05-20",
          "accepted_at": "2026-05-13T00:00:00Z"
        }
      },
      "app": {
        "platform_name": "kled.ai",
        "legal_entity": "Nitrility Inc. (Delaware, USA)",
        "active_tos": { "version": "2026-05-20", "url": "https://kled.ai/terms" },
        "active_privacy_policy": { "version": "2026-05-20", "url": "https://kled.ai/privacy" }
      },
      "timestamps": {
        "occurred_at": "2026-05-13T00:00:00Z",
        "uploaded_at": "2026-05-13T00:00:00Z"
      },
      "attestation": {
        "payload_hash": "sha256:<canonical-trace-schema-v1-json>",
        "key_id": "kled-verify-2026-q1",
        "key_url": "https://kled.ai/.well-known/verification-keys.json",
        "signed_at_utc": "2026-05-13T00:00:02Z"
      },
      "provider_payload": {
        "media_id_public": "kmf_8a9c2e7d4b1f0e23"
      }
    },
    "occurred_at": "2026-05-13T00:00:00Z"
  }
]

initial_metadata_rootshould be the provider's deterministic hash of the canonical Trace Schema v1.0 metadata JSON. In the current staging API, Trace stores this value as submitted; hash verification against initial_metadata_json is not enforced yet.

Write API

Submit metadata updates

Later corrections or mutable metadata changes go here. seq must be between 1 and 20 for the same data_id.

POST /webhook/v1/data-audit/metadata-updates:batch
Content-Type: application/json
X-API-Key: <Kled staging key>
X-Provider: kled
X-Batch-Id: kled-metadata-000001
[
  {
    "data_id": "11111111-1111-4111-8111-111111111111",
    "seq": 1,
    "prev_metadata_root": "sha256:<previous>",
    "metadata_root": "sha256:<new>",
    "metadata_json": {
      "schema_version": "trace-v1.0",
      "user": { "source_user_id": "kup_123", "kyc_status": "unverified" },
      "app": { "platform_name": "kled.ai" },
      "provider_payload": {
        "media_id_public": "kmf_8a9c2e7d4b1f0e23",
        "reason": "kyc_status_changed"
      }
    },
    "occurred_at": "2026-05-13T00:00:01Z"
  }
]

Optional NDJSON variants exist for large backlog tooling at /webhook/v1/data-audit/data-ids:batch-ndjson and /webhook/v1/data-audit/metadata-updates:batch-ndjson. Both require Content-Encoding: gzip.

Read API

Look up & search

Read endpoints are keyed by Story data_id. Provider is returned as a field and can be used as an optional filter or searched directly.

GET /api/v1/data-audit/data-ids/<data_id>
GET /api/v1/data-audit/data-ids/<data_id>/metadatas
GET /api/v1/data-audit/search?field=file.media_category&value=video&limit=100

Search

Indexed (exact-match) fields

  • provider
  • source_record_id
  • media_id_public
  • file.content_sha256 (asset_hash alias)
  • file.mime_type
  • file.media_category
  • collection_id
  • customer_id
  • task_id
  • user.source_user_id
  • user.kyc_status
  • user.kyc_country
  • contributor.geo_region
  • tos_hash
  • privacy_policy_hash

Perceptual hashes (phash64, dhash64, ahash64, keyframe_phashes) and md5 may be preserved in payloads, but they are not indexed.

Constraints

Limits & retry behavior

Max request body: 25 MiB
Max serialized record: 350 KiB
Max metadata updates per data_id: 100
  • — Retry 502 / 503 / 504, network timeouts, and 429 with exponential backoff + jitter.
  • — Do not retry validation/auth 4xx until fixed.
  • — Keep data_id, request body, and X-Batch-Id stable across retries.
  • — The write path is idempotent for the same data_id, event key, and event hash.
  • — Same data_id + event key submitted with different metadata is treated as a conflict and rejected.