Skip to content

Changelog

Changes to the /v1 API and to this documentation, newest first.

/v1 is additive: new endpoints, new fields and new optional parameters can appear at any time, and a client must ignore fields it does not recognise. Anything that would break a conforming client cuts /v2 instead — so nothing on this page below a Breaking label will ever require you to change working code.


New — Trust Center access requests can be decided from your own systems. Approve or reject a pending request with POST /v1/trust-center/access-requests/{id}/approve and POST /v1/trust-center/access-requests/{id}/reject, and read one with GET /v1/trust-center/access-requests/{id}. Deciding needs the new scope trust-center-access:write; a decision already made answers 409 ACCESS_REQUEST_ALREADY_DECIDED. The visitor’s access link is always emailed to them and the token is never returned to you. Access requests gain decidedVia, decidedByApiClientId and decisionReference, and the trustcenter.access_approved and trustcenter.access_rejected webhook payloads now carry decidedBy. Guide.

New — Trust Center documents carry a protection policy. GET /v1/trust-center/resources gains isRestricted (never part of a standard approval — granted only by name), ndaRequired (the visitor signs the NDA before the file is served, while the organization’s NDA requirement is on) and downloadAllowed (false = view-only). isGated keeps its meaning and is true for restricted documents too. GET /v1/trust-center/access-requests gains requestedResourceIds — the restricted documents a visitor asked for by name, which is a request and not a grant.

New — the Trust Center document access log is pullable. GET /v1/trust-center/access-events lists every read of a Trust Center document by a visitor holding access — who, which document, when, how it was served and whether it was watermarked — newest first and cursor-paginated. Scope: trust-center-analytics:read, which is new and mintable from today.

The document fields are a snapshot taken when the file was served, so a later rename or re-upload does not rewrite history; events recorded before snapshots existed carry snapshotReconstructed: true. Push delivery is the new trustcenter.resource_downloaded webhook, whose accessEventId is the event’s id here; trustcenter.access_rejected is new alongside it.

Changed — webhook deliveries are retried, and each webhook says how. A failed delivery is no longer dropped: a timeout, a network error, 408, 429 or a 5xx (other than 501/505) is retried — by default up to 6 attempts over about 6 hours, and on a 429 or 503 after the receiver’s Retry-After. Any other 4xx, 410 Gone, an unfollowable redirect and a blocked address fail at once. Delivery is therefore at-least-once: dedupe on X-Vendorica-Delivery, which is identical on every attempt, and read the new X-Vendorica-Delivery-Attempt header for the attempt number. The webhooks guide has the full table.

Webhooks gain retryPolicy and failureHandling, readable on every webhook and settable on POST /v1/webhooks and PATCH /v1/webhooks/{id}; both objects are partial on write. 410 Gone now suspends the webhook unless failureHandling.disableOnGone is false. Deliveries from GET /v1/webhooks/{id}/deliveries can be retrying, and carry attemptCount, nextAttemptAt, lastFailureClass and every attempt in attempts.

Fixed — the published Webhook schema named a trigger string. The endpoints have returned a triggers array since a webhook could subscribe to more than one event; the reference now says so. No response changed.


New — segregation-of-duties findings are pullable. GET /v1/sod/violations lists every case where one holder was found with both halves of a duty pair your organization keeps separate, filterable by status, ruleId, subjectType and subjectId. Scope: sod:read.

Two things worth knowing before you correlate on it. Read the rung from evidence.enforcementAtDetection, not from the rule as it stands now — a rule promoted since is a different statement about the same finding. And accepted / resolved are terminal: a conflict that recurs is filed as a new violation rather than reopening the old one, so poll on detectedAt for new findings and re-read a row to pick up its decision. Push delivery of the same finding is the sod.violation_detected webhook.


POST /v1/incidents accepts businessFunctionId. An incident can now name the critical or important function it affected, so DORA Articles 17–19 are answerable per function rather than only per organisation. Optional, and absent it behaves exactly as before — POST /v1/incidents.


Fixed — createdTo on the audit log now covers the day it names. A bare date sent to GET /v1/audit-log was compared against midnight at the start of that day, so createdFrom=2026-09-01 with createdTo=2026-09-01 matched nothing. It now runs through 2026-09-01T23:59:59.999Z. If you worked around this by sending the next day as createdTo, that request now returns an extra day — send the day you mean. A createdTo carrying a time is unchanged and is still used exactly as given.


Changed — an idempotent evidence replay redacts sensitive metadata, like every other read. A digest-matched replay of POST /v1/controls/{controlId}/evidence returned the existing row’s summary, description and contentFilename in full, even where the same row’s listing redacts them and its download answers 403. Evidence flagged isSensitive is readable by its uploader, administrators and auditors; an API key is none of those, so those three fields now come back null / "(sensitive)" on a replay for such a caller. The replay itself is unchanged — still 200 with Idempotent-Replay: true, still safe to retry — and a caller who may view the row sees no difference.


New — the policy register answers which version is in force. Each row of GET /v1/policies now carries currentVersionNumber / currentVersionPublishedAt for the published version and latestVersionNumber / latestVersionApprovalStatus for the one being worked on, plus versionCount. The two are routinely different — an approved v2 in force under a v3 in review — so neither is derivable from the other, and answering “is a revision in flight” previously cost a {id}/versions request per policy.


Changed — risk scores follow the organization’s own calculation, and are no longer integers. inherentScore / residualScore on GET /v1/risk-scenarios · {id} were documented as integer and are now number. An organization can choose how likelihood and impact combine — multiply (1–25, the default and what every existing organization is on), sum (2–10) or average (1–5) — and the last of those produces halves. Read the score rather than recomputing it from inherentLikelihood × inherentImpact: that product is only correct for organizations on the default, and the API does not publish which calculation is in force.


New — DORA RoI service type on a contract. A contract now carries ebaIctServiceType, the ITS type of ICT services as one of the 19 eba_TA:S01–S19 members. It is what the Register of Information files in B_02.02 c0060 and B_07.01 c0040, and it is the code rather than a name: the field accepts only members of that closed list, so a label like "SaaS" is rejected rather than stored and later dropped. GET /v1/contracts · {id}.


New — The rest of the risk surface. /v1 carried risk registers and scenarios; it now carries the layers around them. All read-only, all on the existing risks:read scope:

Two field-level notes worth reading before you build against them: an indicator’s direction decides which side of a threshold is a breach, and a trend row’s status is frozen against the thresholds in force when it was measured, so it can disagree with today’s. Both are documented on the operations above.

New — GET /v1/users, under a new users:read scope. A directory — id, email, name, status — so a report can label the ownerUserId that scenarios, contracts and incidents carry. Grant the scope when you create a key; existing keys do not acquire it.


Updated — Rate limits are lower. The per-client budgets are now 300/min reads, 120/min writes and 60/min on the binary upload and download endpoints, down from 1,200 / 300 / 120.

A client that honours Retry-After needs no change. One that paces on a fixed sleep calculated from the old numbers will start seeing 429 — read the budget from the RateLimit-* headers instead, which have always carried it. See rate limits.

The old figures were not sized from observed traffic; they were a comfortable default. If you are doing a bulk migration, ask us to raise the budget on your API client rather than pacing around the default — that override is what it is for.

Docs — A guide to importing vendors and contracts. Import vendors and contracts covers POST /v1/vendors/imports end to end — match keys, upsert semantics, LEI enrichment, and reading the per-row outcome — and is explicit that contracts have no create endpoint, so a migration plans them through the in-app importer instead.

Docs — Every documented response carries an example. All 281 response bodies in the API reference now show a worked example. Success examples are generated from the schema itself, so they cannot contradict the field list beside them; error examples come from the error class the service actually throws, so code and error are the literal strings you will receive.

402 and 409 deliberately carry no example — each maps to several codes, and showing one would document a code you may never receive. Their status descriptions carry the meaning instead.

Docs — These docs were published at developer.vendorica.com.

They went up at docs.vendorica.com first and moved the same day. That address no longer resolves and never had an audience; it is recorded here only so a link someone captured in those few hours has an explanation.


New — Incident reporting. POST /v1/incidents and GET /v1/incidents, GET /v1/incidents/{id}. Scopes incidents:write / incidents:read. DORA reporting clocks are anchored on the incident’s reportedAt, not on when the record was created, so a backfilled incident keeps its real regulatory deadline.

New — Controls, compliance, policies and Trust Center reads.

Endpoint Scope
GET /v1/controls, /controls/{id}, /controls/{id}/mappings controls:read
GET /v1/compliance/posture, /compliance/frameworks/{code} compliance:read
GET /v1/policies, /policies/{id}, /policies/{id}/versions, /policies/{id}/versions/{versionId} policies:read
GET /v1/trust-center/resources, /access-requests, /subscribers, /visitor-tokens trust-center-content:read, trust-center-access:read, trust-center-subscribers:read

New — The risk write half. POST /v1/risk-scenarios and PUT /v1/risk-scenarios/{id}, scope risks:write. Risk registers stay read-only.


Every entry here describes a change that shipped. An entry is written in the same pull request as the change it documents, which is the only way a changelog stays true — one written afterwards is written from memory.

Label each entry with what it does to a client that is already working:

  • New — an endpoint, field or parameter that did not exist. Safe.
  • Updated — behaviour of something that did exist, in a way a conforming client tolerates. Read it anyway.
  • Deprecated — still works, will be removed in a future major version. Always names the replacement and the earliest version it can disappear in.
  • Breaking — cannot appear under /v1. Reserved for a future major.
  • Fixed — the service now does what this documentation already said.
  • Docs — this site changed; the API did not.