Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Vendor Evidence Drift API

Compare customer-supplied vendor evidence snapshots and turn certification, subprocessor, policy, SLA, residency, and attestation drift into reviewable findings.

Quickstart: compare two synthetic vendor evidence snapshots without an account

The public demo runs the real production engine, stores nothing, meters nothing, and requires no API key. The data below is synthetic.

cat > request.json <<'JSON'
{
  "check": {
    "vendorId": "vnd-northwind",
    "vendorName": "Northwind Software",
    "previous": {
      "capturedAt": "2026-02-01",
      "certifications": [
        {
          "framework": "soc2_type2",
          "auditor": "Prior & Co",
          "issuedAt": "2025-02-15",
          "expiresAt": "2026-02-14",
          "scope": [
            "security",
            "availability",
            "confidentiality"
          ],
          "exceptions": [],
          "opinion": "unqualified"
        }
      ],
      "subprocessors": [
        {
          "name": "Cloudmail",
          "country": "US",
          "purpose": "transactional email",
          "processesPersonalData": true
        },
        {
          "name": "Metricly",
          "country": "IE",
          "purpose": "product analytics",
          "processesPersonalData": false
        }
      ],
      "policies": [
        {
          "name": "Information Security Policy",
          "version": "4.1",
          "effectiveAt": "2025-03-01",
          "contentHash": "sha256:9f2c"
        }
      ],
      "slas": [
        {
          "metric": "uptime",
          "uptimeBasisPoints": 9995
        },
        {
          "metric": "support_response",
          "targetMinutes": 240
        }
      ],
      "residency": [
        {
          "dataCategory": "customer_content",
          "countries": [
            "IE",
            "US"
          ]
        }
      ],
      "attestations": [
        {
          "kind": "insurance",
          "provider": "Meridian",
          "issuedAt": "2025-06-01",
          "expiresAt": "2026-05-31",
          "coverageMinor": 1000000000,
          "currency": "USD"
        }
      ]
    },
    "current": {
      "capturedAt": "2026-08-01",
      "certifications": [
        {
          "framework": "soc2_type2",
          "auditor": "Nextgen Assurance",
          "issuedAt": "2026-03-20",
          "expiresAt": "2027-03-19",
          "scope": [
            "security",
            "confidentiality"
          ],
          "exceptions": [
            "Access review evidence incomplete for two of twelve months"
          ],
          "opinion": "unqualified"
        }
      ],
      "subprocessors": [
        {
          "name": "Cloudmail",
          "country": "US",
          "purpose": "transactional email",
          "processesPersonalData": true
        },
        {
          "name": "Metricly",
          "country": "IE",
          "purpose": "product analytics",
          "processesPersonalData": false
        },
        {
          "name": "Supportly",
          "country": "BR",
          "purpose": "customer support tooling",
          "processesPersonalData": true
        }
      ],
      "policies": [
        {
          "name": "Information Security Policy",
          "version": "4.1",
          "effectiveAt": "2025-03-01",
          "contentHash": "sha256:44e1"
        }
      ],
      "slas": [
        {
          "metric": "uptime",
          "uptimeBasisPoints": 9990
        },
        {
          "metric": "support_response",
          "targetMinutes": 480
        }
      ],
      "residency": [
        {
          "dataCategory": "customer_content",
          "countries": [
            "BR",
            "IE",
            "US"
          ]
        }
      ],
      "attestations": [
        {
          "kind": "insurance",
          "provider": "Meridian",
          "issuedAt": "2026-06-01",
          "expiresAt": "2027-05-31",
          "coverageMinor": 500000000,
          "currency": "USD"
        }
      ]
    }
  }
}
JSON

curl -sS -X POST https://vendorevidence-api.com/v1/demo/check \
  -H 'content-type: application/json' \
  --data-binary @request.json

Selected fields from the deterministic 200 response (evaluated at 2026-09-06T20:30:00.000Z for this example):

{
  "report": {
    "vendorId": "vnd-northwind",
    "counts": {
      "info": 1,
      "low": 1,
      "medium": 1,
      "high": 7,
      "critical": 1,
      "total": 11
    },
    "materialChanges": 8,
    "reviewRequired": true,
    "risk": {
      "score": 100,
      "band": "severe",
      "rawPoints": 236,
      "capped": true,
      "signals": [
        {
          "signal": "certification",
          "findings": 4,
          "points": 86,
          "highestSeverity": "critical",
          "codes": [
            "scope_reduced",
            "exception_added_to_report",
            "certification_renewed_late",
            "auditor_changed"
          ]
        },
        {
          "signal": "sla",
          "findings": 2,
          "points": 50,
          "highestSeverity": "high",
          "codes": [
            "sla_target_reduced"
          ]
        },
        {
          "signal": "subprocessor",
          "findings": 1,
          "points": 25,
          "highestSeverity": "high",
          "codes": [
            "subprocessor_added_new_jurisdiction"
          ]
        },
        {
          "signal": "policy",
          "findings": 1,
          "points": 25,
          "highestSeverity": "high",
          "codes": [
            "policy_content_changed_without_version"
          ]
        },
        {
          "signal": "residency",
          "findings": 1,
          "points": 25,
          "highestSeverity": "high",
          "codes": [
            "data_residency_changed"
          ]
        },
        {
          "signal": "attestation",
          "findings": 2,
          "points": 25,
          "highestSeverity": "high",
          "codes": [
            "insurance_coverage_reduced",
            "attestation_renewed"
          ]
        }
      ],
      "derivation": [
        "points per finding: critical 45, high 25, medium 12, low 4, info 0",
        "certification: 4 findings — scope_reduced (critical, 45) + exception_added_to_report (high, 25) + certification_renewed_late (medium, 12) + auditor_changed (low, 4) = 86",
        "subprocessor: 1 finding — subprocessor_added_new_jurisdiction (high, 25) = 25",
        "policy: 1 finding — policy_content_changed_without_version (high, 25) = 25",
        "sla: 2 findings — sla_target_reduced (high, 25) + sla_target_reduced (high, 25) = 50",
        "residency: 1 finding — data_residency_changed (high, 25) = 25",
        "attestation: 2 findings — insurance_coverage_reduced (high, 25) + attestation_renewed (info, 0) = 25",
        "raw total = 236 across 11 findings",
        "score = min(236, 100) = 100 — capped, so rawPoints carries the real magnitude",
        "band = severe (65-100)"
      ]
    },
    "findings": [
      {
        "code": "scope_reduced",
        "signal": "certification",
        "severity": "critical",
        "material": true,
        "subject": "soc2_type2",
        "detail": "SOC 2 Type II no longer covers availability. The certification itself is still current, so nothing about its status flags this.",
        "recommendedAction": "Treat the removed scope as uncertified from the new report date. Ask why it was dropped, and check whether anything you rely on sits inside it.",
        "data": {
          "removed": [
            "availability"
          ],
          "previousValue": "security, availability, confidentiality",
          "currentValue": "security, confidentiality"
        }
      },
      {
        "code": "exception_added_to_report",
        "signal": "certification",
        "severity": "high",
        "material": true,
        "subject": "soc2_type2",
        "detail": "SOC 2 Type II notes 1 exception not present in the previous report: Access review evidence incomplete for two of twelve months.",
        "recommendedAction": "Read the exception, decide whether it touches a control you rely on, and track the vendor remediation date.",
        "data": {
          "added": [
            "Access review evidence incomplete for two of twelve months"
          ],
          "previousValue": 0,
          "currentValue": 1
        }
      },
      {
        "code": "subprocessor_added_new_jurisdiction",
        "signal": "subprocessor",
        "severity": "high",
        "material": true,
        "subject": "supportly",
        "detail": "Supportly was added in BR for customer support tooling. No subprocessor in the previous snapshot operated in BR.",
        "recommendedAction": "Run a transfer assessment for the new country before the change takes effect, and check the DPA permits it. Objection windows are usually 30 days and start when the vendor publishes, not when you notice.",
        "data": {
          "country": "BR",
          "currentValue": "BR"
        }
      },
      {
        "code": "policy_content_changed_without_version",
        "signal": "policy",
        "severity": "high",
        "material": true,
        "subject": "information security policy",
        "detail": "Information Security Policy still reads version 4.1, but the document digest changed. Any process that watches version numbers saw nothing.",
        "recommendedAction": "Diff the document itself and ask the vendor why the change did not carry a version increment.",
        "data": {
          "previousValue": "sha256:9f2c",
          "currentValue": "sha256:44e1"
        }
      },
      {
        "code": "sla_target_reduced",
        "signal": "sla",
        "severity": "high",
        "material": true,
        "subject": "support_response",
        "detail": "Support response time moved from 4 hours to 8 hours — 4 hours slower than the previous commitment.",
        "recommendedAction": "Compare the new target against what your own customer commitments depend on, and against the contract you signed.",
        "data": {
          "metric": "support_response",
          "previousValue": 240,
          "currentValue": 480,
          "deltaMinutes": 240
        }
      },
      {
        "code": "sla_target_reduced",
        "signal": "sla",
        "severity": "high",
        "material": true,
        "subject": "uptime",
        "detail": "Uptime fell from 99.95% to 99.90%, a reduction of 5 basis points.",
        "recommendedAction": "Compare the new target against what your own customer commitments depend on, and against the contract you signed.",
        "data": {
          "metric": "uptime",
          "previousValue": 9995,
          "currentValue": 9990,
          "deltaBasisPoints": 5
        }
      },
      {
        "code": "data_residency_changed",
        "signal": "residency",
        "severity": "high",
        "material": true,
        "subject": "customer_content",
        "detail": "customer_content may now reside in BR. Previously: IE, US.",
        "recommendedAction": "Assess the added country for transfer restrictions and customer commitments before the change takes effect.",
        "data": {
          "added": [
            "BR"
          ],
          "removed": [],
          "previousValue": "IE, US",
          "currentValue": "BR, IE, US"
        }
      },
      {
        "code": "insurance_coverage_reduced",
        "signal": "attestation",
        "severity": "high",
        "material": true,
        "subject": "insurance",
        "detail": "Cyber insurance cover fell from USD 10,000,000.00 to USD 5,000,000.00, a reduction of USD 5,000,000.00.",
        "recommendedAction": "Compare the new limit against your contractual minimum and against your own worst-case exposure to this vendor.",
        "data": {
          "previousValue": 1000000000,
          "currentValue": 500000000,
          "deltaMinor": 500000000,
          "currency": "USD"
        }
      },
      {
        "code": "certification_renewed_late",
        "signal": "certification",
        "severity": "medium",
        "material": false,
        "subject": "soc2_type2",
        "detail": "SOC 2 Type II lapsed on 2026-02-14 and the replacement was not issued until 2026-03-20, leaving 33 days with no certified coverage.",
        "recommendedAction": "Record the uncovered window. If your own audit period overlaps it, you have an evidence gap to explain and may need a bridge letter.",
        "data": {
          "gapDays": 33,
          "previousValue": "2026-02-14",
          "currentValue": "2026-03-20"
        }
      },
      {
        "code": "auditor_changed",
        "signal": "certification",
        "severity": "low",
        "material": false,
        "subject": "soc2_type2",
        "detail": "SOC 2 Type II was audited by Nextgen Assurance; the previous report was issued by Prior & Co.",
        "recommendedAction": "Confirm the new firm is accredited for the framework, then compare methodology and sampling against the previous report.",
        "data": {
          "previousValue": "Prior & Co",
          "currentValue": "Nextgen Assurance"
        }
      },
      {
        "code": "attestation_renewed",
        "signal": "attestation",
        "severity": "info",
        "material": false,
        "subject": "insurance",
        "detail": "Insurance certificate was reissued on 2026-06-01, previously 2025-06-01.",
        "recommendedAction": "Replace the copy your assessment cites.",
        "data": {
          "previousValue": "2025-06-01",
          "currentValue": "2026-06-01"
        }
      }
    ],
    "warnings": []
  },
  "requestId": "req_example"
}

The first useful result is reviewRequired: true with eight material changes. The critical certification-scope reduction and stable finding codes tell a TPRM team what changed and what to review.

Input contract

The service compares only evidence you supply; it does not crawl a trust center or verify a certificate. Omitted collections mean not observed, not observed-and-empty.

Create and use a free API key

curl -sS -X POST https://vendorevidence-api.com/v1/keys \
  -H 'content-type: application/json' \
  -d '{"email":"you@example.com","name":"github-quickstart","source":{"source":"github","medium":"developer","campaign":"vendor-evidence-drift-github","content":"readme"}}'

curl -sS -X POST https://vendorevidence-api.com/v1/keys/claim \
  -H 'content-type: application/json' \
  -d '{"token":"PASTE_ONE_TIME_TOKEN_FROM_EMAIL"}'

export API_KEY='PASTE_API_KEY_FROM_CLAIM_RESPONSE'

curl -sS -X POST https://vendorevidence-api.com/v1/checks \
  -H "Authorization: Bearer $API_KEY" \
  -H 'content-type: application/json' \
  --data-binary @request.json

The key-request response is 202 and sends a one-time claim token by email. The claim response is the only place the raw API key is returned; store it securely and never commit it. The authenticated endpoint accepts the same request shape as the demo, with the documented production batch limits and metering.

What to do next

Create review tasks from stable finding codes, retain the evidence snapshot that produced them, and rerun on the next vendor publication.

The stable code catalogue for this product is GET /v1/drift-types. Branch on machine-readable codes, not human-readable detail text.

Authentication and troubleshooting

  • 401: the authenticated endpoint did not receive a valid active key. Set API_KEY to the value returned once by /v1/keys/claim; do not send a claim token as a bearer credential.
  • 400 invalid_request: read error.details.path when present and correct the named field. This service does not emit 422; a client-side schema tool may show 422 before a request reaches the API.
  • 429 quota_exceeded or 429 rate_limited: inspect error.code, honor Retry-After when present, and retry with bounded exponential backoff. A quota exhaustion requires a later quota window or plan change, not a tight retry loop.

Every API error has {"error":{"code","message","requestId"}}. Share the request ID with support, never the API key, claim token, or customer payload.

SDKs and authoritative contract

  • Python: ./sdk/python/vendor_evidence_drift.py
  • TypeScript: ./sdk/typescript/index.ts

The live OpenAPI document is authoritative for operations and schemas. This overlay is a customer-runnable example aligned to that contract; it does not replace the OpenAPI document or claim that an unresolved external contract is authoritative.

Distribution attribution

The key request above uses vendor-evidence-drift-github as the stable GitHub campaign. The Postman collection uses postman / collection / vendor-evidence-drift-postman / public-collection. These are attribution inputs, not claims of customers or revenue.

License

MIT

About

Compare customer-supplied vendor evidence states and return certification, subprocessor, SLA, residency, policy, and control-impact drift; this service never fetches vendor documents.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages