{"openapi":"3.1.0","info":{"title":"Vigilo API","version":"1","description":"REST API of your organization's compliance data: read portfolios, sites, their units and equipment, third parties, their contacts and relationships (leases, contracts), compliance types, requirements, their findings and the documents sent (with their files); send documents; create and update portfolios, sites, units, equipment, third parties, their contacts and relationships (the end of a contract stops its reminders); create requirements, change their due date/owner; raise findings and record their correction. Authenticate with an API key created in Settings > API keys. JSON in camelCase, dates in ISO 8601, cursor pagination, 300 requests per minute per key by default (see X-RateLimit-Limit). Version 1 only gains things (new endpoints, fields, optional parameters, response enum values): ignore unknown fields and values in responses; a request body field or a query parameter that is not documented is refused (400 api.unknownField, api.unknownParameter); breaking changes go to /api/v2."},"servers":[{"url":"https://beta.185-211-6-64.sslip.io"}],"security":[{"bearer":[]}],"tags":[{"name":"sites"},{"name":"portfolios","description":"Groups of sites (a fund, a region, a client). Scopes read:sites / write:sites."},{"name":"units","description":"Units of a site (apartments, shops, offices…): what a lease is about. Scopes read:sites / write:sites."},{"name":"assets","description":"Equipment and installations of a site or a unit (lifts, extinguishers, boilers…): what the periodic inspections are about. Scopes read:sites / write:sites."},{"name":"parties","description":"Third parties (suppliers, tenants, insurers…)."},{"name":"relationships","description":"Leases, contracts and assignments of a third party to a site or a unit. Scopes read:parties / write:parties."},{"name":"contacts","description":"The persons of a third party the requests go to. Scopes read:parties / write:parties; the contacts a portal delegation created (insurer, broker) are not listed."},{"name":"compliance-types","description":"What the organization follows (insurance certificate, periodic inspection…). Scope read:requirements."},{"name":"requirements"},{"name":"findings","description":"Findings of a requirement: the reservations of an inspection report, the observations of a visit. Scopes read:requirements / write:requirements; a key raises a finding, takes it in charge and resolves it; a member, or a write:reviews key in their name, verifies, sends back, accepts or reopens."},{"name":"submissions","description":"Documents sent for a requirement (evidence), their review and their files. Scopes read:submissions / write:submissions (send); write:reviews approves, rejects, revokes and puts back to review in the name of the key's creator."},{"name":"reminders","description":"The emails sent to third parties (requests, reminders, receipts), as kept for proof (scope read:reminders), and « remind now » (scope write:reminders)."},{"name":"messages","description":"The thread between the organization and the third party on a requirement: read (scope read:reminders), write to the third party (scope write:reminders)."},{"name":"portal-links","description":"The links that open the portal of a third party to a contact: read without their token (scope read:reminders), issued for your own tool to send and revoked (scope write:portal-links)."},{"name":"audit","description":"The audit journal (scope read:audit), for a SIEM."},{"name":"imports","description":"The starter workbook: the whole base in one .xlsx, checked then imported all or nothing; the last imports, and the undo of one (scope write:import)."},{"name":"exports","description":"The full export of the organization (every table, every document) in one ZIP, built in the background then downloaded, resumable (scope read:export, given by an owner only)."},{"name":"webhooks","description":"Webhook subscriptions of the key (scope write:webhooks), for Power Automate, Logic Apps, Zapier or Make. Bodies and signature: webhooks below and x-webhooks."},{"name":"settings","description":"The organization's configuration: values added to the site types and equipment kinds, default delays of a new type, custom fields, assignment rules. Scopes read:settings / write:settings (a write is what an owner or admin does in Settings)."},{"name":"members","description":"The members of the organization and the pending invitations: access review (scope read:members), invite, change and remove managers and viewers (scope write:members: the key acts in the name of the member who created it, refused once they are no longer owner or admin; administrators are appointed and removed on the screen)."},{"name":"key"}],"paths":{"/api/v1/me":{"get":{"tags":["key"],"operationId":"GetMe","summary":"Get the key and its organization","description":"Connection test; any valid key.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/sites":{"get":{"tags":["sites"],"operationId":"ListSites","summary":"List sites","security":[{"bearer":["read:sites"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"includeArchived","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"}},{"name":"updatedSince","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only the rows whose updatedAt is at or after this instant (ISO 8601 with Z or an offset). Incremental sync: send the time you started the previous sync minus a few minutes (a change being written at that moment may carry an earlier time), then deduplicate by id; add includeArchived=true to see the rows archived since. A party's updatedAt also moves when an official register's answer about it changes (registry); a document's when Vigilo replaces its uploaded bytes by the compressed copy (storedCopy)."},{"name":"code","in":"query","schema":{"type":"string","maxLength":100}},{"name":"portfolioId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"country","in":"query","schema":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO 3166-1 alpha-2, case ignored."}},{"name":"managerUserId","in":"query","schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["none"]}],"description":"The sites of this manager; none: the sites without one."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Site"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["sites"],"operationId":"CreateSite","summary":"Create a site","security":[{"bearer":["write:sites"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":2,"maxLength":160},"code":{"type":["string","null"],"maxLength":30},"siteType":{"type":"string","description":"One of residential, commercial, office, industrial, mixed, public_access, warehouse, other or a type added in the organization settings. Default \"other\"."},"portfolioId":{"type":["string","null"],"format":"uuid"},"addressLine1":{"type":["string","null"],"maxLength":200},"addressLine2":{"type":["string","null"],"maxLength":200},"postalCode":{"type":["string","null"],"maxLength":20},"city":{"type":["string","null"],"maxLength":120},"region":{"type":["string","null"],"maxLength":120},"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO 3166-1 alpha-2; default the organization's country."},"latitude":{"type":["number","null"],"minimum":-90,"maximum":90},"longitude":{"type":["number","null"],"minimum":-180,"maximum":180},"timezone":{"type":["string","null"],"description":"IANA time zone (any case: `europe/madrid` is stored `Europe/Madrid`). In a country with several time zones: the region's when given, mainland Spain's or Portugal's by default (Canary Islands, Azores by postal code), else required."},"managerUserId":{"type":["string","null"],"format":"uuid","description":"An owner, admin or manager of the organization."},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"description":"Trimmed, case-insensitive duplicates dropped."},"customFields":{"type":"object","additionalProperties":true,"description":"Custom fields defined in the organization settings, by identifier. Number and money fields: send JSON numbers (5000000, 12.5)."}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"An administrator is converting or editing the custom fields of these items (`ref.customFieldsLocked`, waited 3 s): nothing was written; try again after `Retry-After`. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/sites/{id}":{"get":{"tags":["sites"],"operationId":"GetSite","summary":"Get a site","security":[{"bearer":["read:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["sites"],"operationId":"UpdateSite","summary":"Update a site","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":160},"code":{"type":["string","null"],"maxLength":30},"siteType":{"type":"string","description":"One of residential, commercial, office, industrial, mixed, public_access, warehouse, other or a type added in the organization settings."},"portfolioId":{"type":["string","null"],"format":"uuid"},"addressLine1":{"type":["string","null"],"maxLength":200},"addressLine2":{"type":["string","null"],"maxLength":200},"postalCode":{"type":["string","null"],"maxLength":20},"city":{"type":["string","null"],"maxLength":120},"region":{"type":["string","null"],"maxLength":120},"country":{"type":"string","pattern":"^[A-Za-z]{2}$","description":"ISO 3166-1 alpha-2; default the organization's country."},"latitude":{"type":["number","null"],"minimum":-90,"maximum":90},"longitude":{"type":["number","null"],"minimum":-180,"maximum":180},"timezone":{"type":["string","null"],"description":"IANA time zone (any case: `europe/madrid` is stored `Europe/Madrid`). In a country with several time zones: the region's when given, mainland Spain's or Portugal's by default (Canary Islands, Azores by postal code), else required."},"managerUserId":{"type":["string","null"],"format":"uuid","description":"An owner, admin or manager of the organization."},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"description":"Trimmed, case-insensitive duplicates dropped."},"customFields":{"type":"object","additionalProperties":true,"description":"Custom fields defined in the organization settings, by identifier. Number and money fields: send JSON numbers (5000000, 12.5)."}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"An administrator is converting or editing the custom fields of these items (`ref.customFieldsLocked`, waited 3 s): nothing was written; try again after `Retry-After`. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["sites"],"operationId":"DeleteSite","summary":"Archive a site","description":"A site sold or closed, as on the screen: its units, equipment and leases are archived with it, and their requirements closed (closedReason subject_archived: reminders stop, portal links of those requirements stop working); POST /sites/{id}/restore (or « Restore » on the screen) brings them back. An archived site stays readable with includeArchived=true; archiving it again answers 204.","security":[{"bearer":["write:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Archived."},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/sites/{id}/restore":{"post":{"tags":["sites"],"operationId":"RestoreSite","summary":"Restore a site","description":"A site archived by mistake (on the screen, by DELETE, or by an import undone): its units, equipment and leases archived with it come back, and its code when no other site took it meanwhile (an import undone gives the code a suffix ~… so that the corrected file loads). Under an archived portfolio: restore the portfolio first. The requirements closed with it reopen (status recomputed). Not archived (a replay): the same answer. The journal records the restore under the key. No body.","security":[{"bearer":["write:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"responses":{"200":{"description":"Restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Site"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `ref.parentArchived` (what holds it is archived: restore that first), `aud.partyAlreadyErased` (an erased third party is never restored), `org.suspended`, `org.closed`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/sites/{id}/compliance-at-date":{"get":{"tags":["sites"],"operationId":"GetSiteComplianceAtDate","summary":"Get the compliance of a site at a date","description":"Was it compliant on 12 March? The requirements attached to the site (the site, its units, its equipment, the third parties working there) as they stood at a past instant, rebuilt from the audit trail, with the approved document that covered the date. Scope read:requirements; ids only (no names). The date is read in each requirement's time zone; without time, the end of that day; today: now. Read only, not audited.","security":[{"bearer":["read:requirements"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"date","in":"query","schema":{"type":"string","format":"date","description":"The date (YYYY-MM-DD): today at the latest, 60 months back at most (the business events kept); absent: today (now)."}},{"name":"time","in":"query","schema":{"type":"string","pattern":"^([01][0-9]|2[0-3]):[0-5][0-9]$","description":"HH:MM (24 h), that minute included; absent: the end of the day."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComplianceAtDate"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`validation.invalid` (malformed date or time, or a time without its date, in `fieldErrors`), `validation.dateInFuture`, `aud.atDateTooOld` (before the audit trail kept), `aud.atDateTooMany` (more than 5 000 requirements).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/portfolios":{"get":{"tags":["portfolios"],"operationId":"ListPortfolios","summary":"List portfolios","security":[{"bearer":["read:sites"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"includeArchived","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"}},{"name":"updatedSince","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only the rows whose updatedAt is at or after this instant (ISO 8601 with Z or an offset). Incremental sync: send the time you started the previous sync minus a few minutes (a change being written at that moment may carry an earlier time), then deduplicate by id; add includeArchived=true to see the rows archived since. A party's updatedAt also moves when an official register's answer about it changes (registry); a document's when Vigilo replaces its uploaded bytes by the compressed copy (storedCopy)."},{"name":"code","in":"query","schema":{"type":"string","maxLength":100,"description":"Exact code: the portfolio your system knows."}},{"name":"managerUserId","in":"query","schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["none"]}],"description":"The portfolios of this manager; none: those without one."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Portfolio"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["portfolios"],"operationId":"CreatePortfolio","summary":"Create a portfolio","security":[{"bearer":["write:sites"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":2,"maxLength":120,"description":"Unique among the non-archived portfolios, case ignored (422 ref.duplicateName with existingId)."},"code":{"type":["string","null"],"maxLength":30,"description":"Your identifier; unique in the organization (422 ref.duplicateCode with existingId)."},"description":{"type":["string","null"],"maxLength":2000},"managerUserId":{"type":["string","null"],"format":"uuid","description":"An owner, admin or manager of the organization."},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"description":"Trimmed, case-insensitive duplicates dropped."}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Portfolio"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/portfolios/{id}":{"get":{"tags":["portfolios"],"operationId":"GetPortfolio","summary":"Get a portfolio","security":[{"bearer":["read:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Portfolio"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["portfolios"],"operationId":"UpdatePortfolio","summary":"Update a portfolio","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120,"description":"Unique among the non-archived portfolios, case ignored (422 ref.duplicateName with existingId)."},"code":{"type":["string","null"],"maxLength":30,"description":"Your identifier; unique in the organization (422 ref.duplicateCode with existingId)."},"description":{"type":["string","null"],"maxLength":2000},"managerUserId":{"type":["string","null"],"format":"uuid","description":"An owner, admin or manager of the organization."},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"description":"Trimmed, case-insensitive duplicates dropped."}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Portfolio"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["portfolios"],"operationId":"DeletePortfolio","summary":"Archive a portfolio","description":"A portfolio no longer used, as on the screen. Holding active sites: 422 ref.hasActiveChildren, unless cascade=true, which archives them with it (their units, equipment and leases; their requirements closed, closedReason subject_archived) — or move them first (PATCH /sites/{id} portfolioId). POST /portfolios/{id}/restore brings everything back. An archived portfolio stays readable with includeArchived=true; archiving it again answers 204.","security":[{"bearer":["write:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"cascade","in":"query","schema":{"type":"boolean","default":false},"description":"true: its active sites are archived with it. Neither true nor false: 422 validation.invalid."}],"responses":{"204":{"description":"Archived."},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/portfolios/{id}/restore":{"post":{"tags":["portfolios"],"operationId":"RestorePortfolio","summary":"Restore a portfolio","description":"A portfolio archived on the screen or by an import undone: the sites archived with it come back with their units, equipment and leases. The requirements closed with it reopen (status recomputed). Not archived (a replay): the same answer. The journal records the restore under the key. No body.","security":[{"bearer":["write:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"responses":{"200":{"description":"Restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Portfolio"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `ref.parentArchived` (what holds it is archived: restore that first), `aud.partyAlreadyErased` (an erased third party is never restored), `org.suspended`, `org.closed`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/units":{"get":{"tags":["units"],"operationId":"ListUnits","summary":"List units","security":[{"bearer":["read:sites"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"includeArchived","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"}},{"name":"updatedSince","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only the rows whose updatedAt is at or after this instant (ISO 8601 with Z or an offset). Incremental sync: send the time you started the previous sync minus a few minutes (a change being written at that moment may carry an earlier time), then deduplicate by id; add includeArchived=true to see the rows archived since. A party's updatedAt also moves when an official register's answer about it changes (registry); a document's when Vigilo replaces its uploaded bytes by the compressed copy (storedCopy)."},{"name":"siteId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"reference","in":"query","schema":{"type":"string","maxLength":40,"description":"Exact reference, case ignored; with siteId: the unit your system knows."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Unit"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["units"],"operationId":"CreateUnit","summary":"Create an unit","security":[{"bearer":["write:sites"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["siteId","reference"],"properties":{"siteId":{"type":"string","format":"uuid","description":"A non-archived site of the organization: unknown, 422 validation.invalid with fieldErrors.siteId; archived, 422 ref.parentArchived."},"reference":{"type":"string","minLength":1,"maxLength":40,"description":"Unique in its site, case ignored (422 ref.duplicateReference with existingId: a replayed POST finds the unit)."},"name":{"type":["string","null"],"maxLength":120},"unitType":{"type":"string","enum":["apartment","house","shop","office","storage","parking","warehouse","other"],"default":"other"},"floor":{"type":["string","null"],"maxLength":10},"areaM2":{"type":["number","null"],"exclusiveMinimum":0,"maximum":1000000,"description":"Square metres, two decimals at most."},"occupancyStatus":{"type":"string","enum":["occupied","vacant","unknown"],"default":"unknown","description":"Recomputed from the leases of the unit each time one starts or ends."},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"description":"Trimmed, case-insensitive duplicates dropped."}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Unit"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/units/{id}":{"get":{"tags":["units"],"operationId":"GetUnit","summary":"Get an unit","security":[{"bearer":["read:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Unit"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["units"],"operationId":"UpdateUnit","summary":"Update an unit","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reference":{"type":"string","minLength":1,"maxLength":40,"description":"Unique in its site, case ignored (422 ref.duplicateReference with existingId: a replayed POST finds the unit)."},"name":{"type":["string","null"],"maxLength":120},"unitType":{"type":"string","enum":["apartment","house","shop","office","storage","parking","warehouse","other"]},"floor":{"type":["string","null"],"maxLength":10},"areaM2":{"type":["number","null"],"exclusiveMinimum":0,"maximum":1000000,"description":"Square metres, two decimals at most."},"occupancyStatus":{"type":"string","enum":["occupied","vacant","unknown"],"description":"Recomputed from the leases of the unit each time one starts or ends."},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"description":"Trimmed, case-insensitive duplicates dropped."}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Unit"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["units"],"operationId":"DeleteUnit","summary":"Archive an unit","description":"As on the screen: its equipment and its leases are archived with it, and their requirements closed (closedReason subject_archived: reminders stop); POST /units/{id}/restore brings them back. An archived unit stays readable with includeArchived=true; archiving it again answers 204.","security":[{"bearer":["write:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Archived."},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/units/{id}/restore":{"post":{"tags":["units"],"operationId":"RestoreUnit","summary":"Restore an unit","description":"A unit archived by mistake: its equipment and leases archived with it come back, and its reference when no other unit of the site took it meanwhile. Under an archived site: restore the site first. The requirements closed with it reopen (status recomputed). Not archived (a replay): the same answer. The journal records the restore under the key. No body.","security":[{"bearer":["write:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"responses":{"200":{"description":"Restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Unit"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `ref.parentArchived` (what holds it is archived: restore that first), `aud.partyAlreadyErased` (an erased third party is never restored), `org.suspended`, `org.closed`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/assets":{"get":{"tags":["assets"],"operationId":"ListAssets","summary":"List assets","security":[{"bearer":["read:sites"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"includeArchived","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"}},{"name":"updatedSince","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only the rows whose updatedAt is at or after this instant (ISO 8601 with Z or an offset). Incremental sync: send the time you started the previous sync minus a few minutes (a change being written at that moment may carry an earlier time), then deduplicate by id; add includeArchived=true to see the rows archived since. A party's updatedAt also moves when an official register's answer about it changes (registry); a document's when Vigilo replaces its uploaded bytes by the compressed copy (storedCopy)."},{"name":"siteId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"unitId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"assetKind","in":"query","schema":{"type":"string","maxLength":60}},{"name":"reference","in":"query","schema":{"type":"string","maxLength":100,"description":"Exact reference, case ignored: the equipment your maintenance tool knows."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Asset"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["assets"],"operationId":"CreateAsset","summary":"Create an asset","security":[{"bearer":["write:sites"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["siteId","assetKind","name"],"properties":{"siteId":{"type":"string","format":"uuid","description":"A non-archived site of the organization: unknown, 422 validation.invalid with fieldErrors.siteId; archived, 422 ref.parentArchived."},"unitId":{"type":["string","null"],"format":"uuid","description":"A non-archived unit of the asset's site (422 ref.unitSiteMismatch otherwise); null: the common parts. Its requirements follow."},"assetKind":{"type":"string","description":"One of fire_extinguisher, fire_hose_reel, fire_alarm, sprinkler, smoke_extraction, emergency_lighting, fire_door, dry_riser, defibrillator, lift, escalator, automatic_door, electrical_installation, lightning_protection, gas_installation, boiler, chimney, ventilation, hvac, cooling_tower, water_system, pool, playground, sports_equipment, pressure_equipment, lifting_equipment, work_equipment, forklift, racking, dock_equipment, portable_appliance, vehicle, generator, solar_installation, tank, other or a kind added in the organization settings. Changing it re-evaluates the assignment rules."},"name":{"type":"string","minLength":1,"maxLength":200},"reference":{"type":["string","null"],"maxLength":100,"description":"Your identifier of the equipment. Through the API, a reference another non-archived asset of the site already carries (case ignored) answers 422 ref.duplicateReference with existingId: a replayed POST finds the asset instead of doubling it and its inspections."},"serialNumber":{"type":["string","null"],"maxLength":100},"manufacturer":{"type":["string","null"],"maxLength":120},"model":{"type":["string","null"],"maxLength":120},"installedOn":{"type":["string","null"],"format":"date","description":"Not in the future (site's time zone)."},"locationDetail":{"type":["string","null"],"maxLength":200},"quantity":{"type":"integer","minimum":1,"default":1,"description":"At most the organization's ceiling (10 000 by default; above it, 422 validation.invalid with fieldErrors.quantity, the message naming the ceiling). A quantity stored before the ceiling was lowered may be sent back unchanged, or decreased."},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"description":"Trimmed, case-insensitive duplicates dropped."}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Asset"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/assets/{id}":{"get":{"tags":["assets"],"operationId":"GetAsset","summary":"Get an asset","security":[{"bearer":["read:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Asset"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["assets"],"operationId":"UpdateAsset","summary":"Update an asset","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"unitId":{"type":["string","null"],"format":"uuid","description":"A non-archived unit of the asset's site (422 ref.unitSiteMismatch otherwise); null: the common parts. Its requirements follow."},"assetKind":{"type":"string","description":"One of fire_extinguisher, fire_hose_reel, fire_alarm, sprinkler, smoke_extraction, emergency_lighting, fire_door, dry_riser, defibrillator, lift, escalator, automatic_door, electrical_installation, lightning_protection, gas_installation, boiler, chimney, ventilation, hvac, cooling_tower, water_system, pool, playground, sports_equipment, pressure_equipment, lifting_equipment, work_equipment, forklift, racking, dock_equipment, portable_appliance, vehicle, generator, solar_installation, tank, other or a kind added in the organization settings. Changing it re-evaluates the assignment rules."},"name":{"type":"string","minLength":1,"maxLength":200},"reference":{"type":["string","null"],"maxLength":100,"description":"Your identifier of the equipment. Through the API, a reference another non-archived asset of the site already carries (case ignored) answers 422 ref.duplicateReference with existingId: a replayed POST finds the asset instead of doubling it and its inspections."},"serialNumber":{"type":["string","null"],"maxLength":100},"manufacturer":{"type":["string","null"],"maxLength":120},"model":{"type":["string","null"],"maxLength":120},"installedOn":{"type":["string","null"],"format":"date","description":"Not in the future (site's time zone)."},"locationDetail":{"type":["string","null"],"maxLength":200},"quantity":{"type":"integer","minimum":1,"description":"At most the organization's ceiling (10 000 by default; above it, 422 validation.invalid with fieldErrors.quantity, the message naming the ceiling). A quantity stored before the ceiling was lowered may be sent back unchanged, or decreased."},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"description":"Trimmed, case-insensitive duplicates dropped."}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Asset"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["assets"],"operationId":"DeleteAsset","summary":"Archive an asset","description":"Equipment taken out of service: as on the screen, its requirements are closed (closedReason subject_archived: reminders stop); POST /assets/{id}/restore reopens them. An archived asset stays readable with includeArchived=true; archiving it again answers 204.","security":[{"bearer":["write:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Archived."},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/assets/{id}/restore":{"post":{"tags":["assets"],"operationId":"RestoreAsset","summary":"Restore an asset","description":"Equipment archived by mistake. Under an archived site or unit: restore it first. The requirements closed with it reopen (status recomputed). Not archived (a replay): the same answer. The journal records the restore under the key. No body.","security":[{"bearer":["write:sites"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"responses":{"200":{"description":"Restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Asset"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `ref.parentArchived` (what holds it is archived: restore that first), `aud.partyAlreadyErased` (an erased third party is never restored), `org.suspended`, `org.closed`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/parties":{"get":{"tags":["parties"],"operationId":"ListParties","summary":"List third parties","security":[{"bearer":["read:parties"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"includeArchived","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"}},{"name":"updatedSince","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only the rows whose updatedAt is at or after this instant (ISO 8601 with Z or an offset). Incremental sync: send the time you started the previous sync minus a few minutes (a change being written at that moment may carry an earlier time), then deduplicate by id; add includeArchived=true to see the rows archived since. A party's updatedAt also moves when an official register's answer about it changes (registry); a document's when Vigilo replaces its uploaded bytes by the compressed copy (storedCopy)."},{"name":"externalRef","in":"query","schema":{"type":"string","maxLength":200}},{"name":"registrationNumber","in":"query","schema":{"type":"string","maxLength":50,"description":"Company registration number; punctuation, spaces and case ignored."}},{"name":"employerPartyId","in":"query","schema":{"type":"string","format":"uuid","description":"The individuals who work for this company."}},{"name":"vatNumber","in":"query","schema":{"type":"string","maxLength":50,"description":"VAT number; punctuation, spaces and case ignored."}},{"name":"role","in":"query","schema":{"type":"string","enum":["tenant","supplier","subcontractor","contractor","service_provider","inspection_body","broker","employee","owner","other"]}},{"name":"q","in":"query","schema":{"type":"string","minLength":2,"maxLength":100,"description":"Name, legal name or email containing this text, case and accents ignored (the search of the screen)."}},{"name":"email","in":"query","schema":{"type":"string","maxLength":254,"description":"Exact email of the third party, case ignored."}},{"name":"managerUserId","in":"query","schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["none"]}],"description":"The third parties of this manager; none: those without one."}},{"name":"identityProposal","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false","description":"true: only the third parties whose contact proposed an identity correction from the portal, awaiting a decision (identityProposal not null)."}},{"name":"complianceStatus","in":"query","style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","enum":["non_compliant","pending","compliant","none"]},"minItems":1},"description":"One compliance status, or several separated by commas (complianceStatus=non_compliant,pending): e.g. the suppliers whose payment to hold."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Party"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["parties"],"operationId":"CreateParty","summary":"Create a third party","security":[{"bearer":["write:parties"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["roles"],"properties":{"kind":{"type":"string","enum":["company","individual"],"default":"company"},"displayName":{"type":["string","null"],"maxLength":200,"description":"Required for a company (2 characters at least); for an individual, default \"firstName lastName\"."},"legalName":{"type":["string","null"],"maxLength":200},"firstName":{"type":["string","null"],"maxLength":100,"description":"Required for an individual."},"lastName":{"type":["string","null"],"maxLength":100,"description":"Required for an individual."},"roles":{"type":"array","items":{"type":"string","enum":["tenant","supplier","subcontractor","contractor","service_provider","inspection_body","broker","employee","owner","other"]},"minItems":1},"registrationNumber":{"type":["string","null"],"maxLength":40,"description":"Same number as an active third party: 422 ref.duplicateRegistration unless duplicateOverride is given."},"vatNumber":{"type":["string","null"],"maxLength":30},"email":{"type":["string","null"],"format":"email","maxLength":254,"description":"The requests go to contacts: when no contact of the third party receives them by email, a contact is created from this address (primary when it has none; an existing contact is never overwritten)."},"phone":{"type":["string","null"],"maxLength":40,"description":"Stored in E.164 (country of the third party)."},"addressLine1":{"type":["string","null"],"maxLength":200},"addressLine2":{"type":["string","null"],"maxLength":200},"postalCode":{"type":["string","null"],"maxLength":20},"city":{"type":["string","null"],"maxLength":120},"region":{"type":["string","null"],"maxLength":120},"country":{"type":"string","pattern":"^[A-Za-z]{2}$"},"locale":{"type":["string","null"],"enum":["en","fr","de","es","it","pt","nl","pl","sv","da","nb","fi","cs","ro","hu","el","tr","ja","zh","ar"]},"timezone":{"type":["string","null"]},"externalRef":{"type":["string","null"],"maxLength":100,"description":"Your identifier; unique in the organization."},"employerPartyId":{"type":["string","null"],"format":"uuid","description":"Individuals only: the company they work for, an active company among your third parties (422 ref.employerInvalid otherwise; ref.employerIndividualOnly on a company). null removes it."},"managerUserId":{"type":["string","null"],"format":"uuid","description":"An owner, admin or manager of the organization who sees the third party (422 ref.invalidManager, ref.managerOutOfScope). null removes them."},"status":{"type":"string","enum":["active","inactive"],"default":"active"},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"description":"Trimmed, case-insensitive duplicates dropped."},"customFields":{"type":"object","additionalProperties":true,"description":"Custom fields defined in the organization settings, by identifier. Number and money fields: send JSON numbers (5000000, 12.5)."},"duplicateOverride":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","minLength":10,"maxLength":500}},"description":"Create or save despite a registration duplicate; the reason is audited."},"relationship":{"type":"object","required":["relationType","startsOn"],"description":"Optional relationship to a site or a unit, created in the same operation.","properties":{"siteId":{"type":["string","null"],"format":"uuid"},"unitId":{"type":["string","null"],"format":"uuid"},"relationType":{"type":"string","enum":["lease","contract","assignment","maintenance","employment","other"]},"reference":{"type":["string","null"],"maxLength":60},"startsOn":{"type":"string","format":"date"},"endsOn":{"type":["string","null"],"format":"date"}}}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Party"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"An administrator is converting or editing the custom fields of these items (`ref.customFieldsLocked`, waited 3 s): nothing was written; try again after `Retry-After`. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/parties/{id}":{"get":{"tags":["parties"],"operationId":"GetParty","summary":"Get a third party","security":[{"bearer":["read:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Party"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["parties"],"operationId":"UpdateParty","summary":"Update a third party","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["company","individual"]},"displayName":{"type":["string","null"],"maxLength":200,"description":"Required for a company (2 characters at least); for an individual, default \"firstName lastName\"."},"legalName":{"type":["string","null"],"maxLength":200},"firstName":{"type":["string","null"],"maxLength":100,"description":"Required for an individual."},"lastName":{"type":["string","null"],"maxLength":100,"description":"Required for an individual."},"roles":{"type":"array","items":{"type":"string","enum":["tenant","supplier","subcontractor","contractor","service_provider","inspection_body","broker","employee","owner","other"]},"minItems":1},"registrationNumber":{"type":["string","null"],"maxLength":40,"description":"Same number as an active third party: 422 ref.duplicateRegistration unless duplicateOverride is given."},"vatNumber":{"type":["string","null"],"maxLength":30},"email":{"type":["string","null"],"format":"email","maxLength":254,"description":"The requests go to contacts: when no contact of the third party receives them by email, a contact is created from this address (primary when it has none; an existing contact is never overwritten)."},"phone":{"type":["string","null"],"maxLength":40,"description":"Stored in E.164 (country of the third party)."},"addressLine1":{"type":["string","null"],"maxLength":200},"addressLine2":{"type":["string","null"],"maxLength":200},"postalCode":{"type":["string","null"],"maxLength":20},"city":{"type":["string","null"],"maxLength":120},"region":{"type":["string","null"],"maxLength":120},"country":{"type":"string","pattern":"^[A-Za-z]{2}$"},"locale":{"type":["string","null"],"enum":["en","fr","de","es","it","pt","nl","pl","sv","da","nb","fi","cs","ro","hu","el","tr","ja","zh","ar"]},"timezone":{"type":["string","null"]},"externalRef":{"type":["string","null"],"maxLength":100,"description":"Your identifier; unique in the organization."},"employerPartyId":{"type":["string","null"],"format":"uuid","description":"Individuals only: the company they work for, an active company among your third parties (422 ref.employerInvalid otherwise; ref.employerIndividualOnly on a company). null removes it."},"managerUserId":{"type":["string","null"],"format":"uuid","description":"An owner, admin or manager of the organization who sees the third party (422 ref.invalidManager, ref.managerOutOfScope). null removes them."},"status":{"type":"string","enum":["active","inactive"]},"tags":{"type":"array","items":{"type":"string","maxLength":40},"maxItems":20,"description":"Trimmed, case-insensitive duplicates dropped."},"customFields":{"type":"object","additionalProperties":true,"description":"Custom fields defined in the organization settings, by identifier. Number and money fields: send JSON numbers (5000000, 12.5)."},"duplicateOverride":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","minLength":10,"maxLength":500}},"description":"Create or save despite a registration duplicate; the reason is audited."}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Party"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"An administrator is converting or editing the custom fields of these items (`ref.customFieldsLocked`, waited 3 s): nothing was written; try again after `Retry-After`. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["parties"],"operationId":"DeleteParty","summary":"Archive a third party","description":"A third party you no longer work with (deactivated in your ERP), as on the screen: its contacts and relationships are archived with it, its requirements closed (closedReason subject_archived: reminders stop) and its portal links revoked. Checks entrusted to it as a provider are released. POST /parties/{id}/restore brings them back (portal links and released checks excepted). An archived party stays readable with includeArchived=true; archiving it again answers 204.","security":[{"bearer":["write:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Archived."},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/parties/{id}/restore":{"post":{"tags":["parties"],"operationId":"RestoreParty","summary":"Restore a third party","description":"A third party archived by mistake (on the screen, by DELETE, or by an import undone): its contacts and relationships archived with it come back. Its portal links stay revoked (issue new ones: POST /portal-links) and the checks it was released from as a provider are not given back. The requirements closed with it reopen (status recomputed). Not archived (a replay): the same answer. The journal records the restore under the key. No body.","security":[{"bearer":["write:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"responses":{"200":{"description":"Restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Party"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `ref.parentArchived` (what holds it is archived: restore that first), `aud.partyAlreadyErased` (an erased third party is never restored), `org.suspended`, `org.closed`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/parties/{id}/compliance-at-date":{"get":{"tags":["parties"],"operationId":"GetPartyComplianceAtDate","summary":"Get the compliance of a third party at a date","description":"Was it compliant on 12 March? The requirements of the third party (as subject) as they stood at a past instant, rebuilt from the audit trail, with the approved document that covered the date. Scope read:requirements; ids only (no names). The date is read in each requirement's time zone; without time, the end of that day; today: now. Read only, not audited.","security":[{"bearer":["read:requirements"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"date","in":"query","schema":{"type":"string","format":"date","description":"The date (YYYY-MM-DD): today at the latest, 60 months back at most (the business events kept); absent: today (now)."}},{"name":"time","in":"query","schema":{"type":"string","pattern":"^([01][0-9]|2[0-3]):[0-5][0-9]$","description":"HH:MM (24 h), that minute included; absent: the end of the day."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComplianceAtDate"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`validation.invalid` (malformed date or time, or a time without its date, in `fieldErrors`), `validation.dateInFuture`, `aud.atDateTooOld` (before the audit trail kept), `aud.atDateTooMany` (more than 5 000 requirements).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/parties/{id}/decide-identity":{"post":{"tags":["parties"],"operationId":"DecidePartyIdentityProposal","summary":"Apply or dismiss the identity correction a third party proposed","description":"A company's contact proposes from its portal to correct its legal name, identifiers, phone or address (identityProposal); the party is never written by the portal. As on the party page: apply takes the fields you keep (fields, all of them when absent) through the same update as PATCH /parties/{id} — identifiers and phone checked, a registration number held by another party refused, assignment rules re-evaluated, history under the key — or dismiss leaves the party as it is. Either way the portal shows the decision for 30 days. A PATCH that gives the party every proposed value closes the proposal as applied too. The answer is the party.","security":[{"bearer":["write:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["action","proposalId"],"properties":{"action":{"type":"string","enum":["apply","dismiss"],"description":"apply: the fields kept take the proposed values through the party update (checks, blocking duplicate, rules, history). dismiss: nothing changes; the portal shows « Correction not kept » for 30 days."},"proposalId":{"type":"string","format":"uuid","description":"identityProposal.id as you read it (GET /parties/{id}): replaced or decided since, 409 ref.identityProposalStale (read it again)."},"fields":{"type":"array","items":{"type":"string","enum":["legalName","registrationNumber","vatNumber","phone","addressLine1","addressLine2","postalCode","city","region","country"]},"minItems":1,"description":"With apply: the fields to take, among those of identityProposal.proposed; absent: all of them. Not sent with dismiss."}},"additionalProperties":false}}}},"responses":{"200":{"description":"The third party after the decision","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Party"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The proposal was decided or replaced by a newer one since you read it (`ref.identityProposalStale`: read the party again). A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `validation.invalid` with `fieldErrors` (action, proposalId: `validation.required` or `ref.invalidReference` for an id that is not this party's proposal, fields: `validation.optionInvalid` with the allowed fields), `ref.archived` (archived party), the errors of PATCH /parties/{id} (a registration number another party holds), `org.suspended`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/calendar.ics":{"get":{"tags":["key"],"operationId":"GetCalendar","summary":"Get the deadlines as a calendar feed","description":"iCalendar feed. Scope read:calendar only; the key may be passed as the `key` query parameter.","security":[{"bearer":[]}],"parameters":[{"name":"key","in":"query","required":false,"schema":{"type":"string"},"description":"The calendar key (alternative to the Authorization header)."}],"responses":{"200":{"description":"iCalendar (RFC 5545).","content":{"text/calendar":{"schema":{"type":"string"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/requirements":{"get":{"tags":["requirements"],"operationId":"ListRequirements","summary":"List requirements","security":[{"bearer":["read:requirements"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"includeArchived","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"}},{"name":"updatedSince","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only the rows whose updatedAt is at or after this instant (ISO 8601 with Z or an offset). Incremental sync: send the time you started the previous sync minus a few minutes (a change being written at that moment may carry an earlier time), then deduplicate by id; add includeArchived=true to see the rows archived since. A party's updatedAt also moves when an official register's answer about it changes (registry); a document's when Vigilo replaces its uploaded bytes by the compressed copy (storedCopy)."},{"name":"status","in":"query","style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","enum":["not_requested","requested","submitted","in_review","rejected","compliant","expiring_soon","overdue","expired","waived","closed"]},"minItems":1},"description":"One status, or several separated by commas (status=overdue,expired)."},{"name":"includeClosed","in":"query","schema":{"type":"string","enum":["true","false"],"default":"true","description":"false: leave out the closed requirements (ended relationship, no longer applicable), as the application's list does by default."}},{"name":"bucket","in":"query","schema":{"type":"string","enum":["compliant","non_compliant","pending","excluded"],"description":"Dashboard group (see the bucket field): bucket=non_compliant gives the dashboard's non-compliant count."}},{"name":"complianceTypeId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"typeCode","in":"query","schema":{"type":"string","maxLength":60,"description":"Code of the compliance type, case ignored."}},{"name":"ownerUserId","in":"query","schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["none"]}],"description":"The owner; none: requirements without owner."}},{"name":"subjectType","in":"query","schema":{"type":"string","enum":["party","site","unit","asset","organization"]}},{"name":"siteId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"unitId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"assetId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"portfolioId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"partyId","in":"query","schema":{"type":"string","format":"uuid","description":"The third party that provides the evidence: the subject for a third-party subject, or the provider in charge of a site, unit, asset or organization requirement. To follow a party's own compliance, keep the rows whose subjectType is party."}},{"name":"dueBefore","in":"query","schema":{"type":"string","format":"date","description":"Due on or before this date."}},{"name":"dueAfter","in":"query","schema":{"type":"string","format":"date","description":"Due on or after this date."}},{"name":"direction","in":"query","schema":{"type":"string","enum":["inbound","outbound","all"],"default":"inbound","description":"Absent: inbound only, unchanged for an organization without outbound requirements."}},{"name":"notConcerned","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false","description":"true: only the requirements whose third party said « This does not concern me », awaiting a decision (notConcerned not null)."}},{"name":"handling","in":"query","schema":{"type":"string","enum":["platform","client"],"description":"Requirements followed up by the Vigilo team (platform) or by the organization (client), as their handling field reads."}},{"name":"q","in":"query","schema":{"type":"string","minLength":2,"maxLength":100,"description":"The search of the screen: type name (in the organization's language), subject name, site name or a custom field value containing this text, case and accents ignored. Third-party names are searched only by a key with `read:parties`, site, unit and equipment names only with `read:sites`."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Requirement"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["requirements"],"operationId":"CreateRequirement","summary":"Create a requirement","security":[{"bearer":["write:requirements"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["subjectType"],"anyOf":[{"required":["complianceTypeId"]},{"required":["complianceTypeCode"]}],"properties":{"complianceTypeId":{"type":"string","format":"uuid","description":"An active compliance type of the organization, with a published version, for this subject type (see GET /compliance-types). Or complianceTypeCode, not both."},"complianceTypeCode":{"type":"string","maxLength":60,"description":"Alternative to complianceTypeId: the code of the type (GET /compliance-types), case ignored. Unknown: 422 with fieldErrors.complianceTypeCode."},"subjectType":{"type":"string","enum":["party","site","unit","asset","organization"]},"subjectId":{"type":"string","format":"uuid","description":"The site, unit, asset or third party; ignored for the organization subject."},"relationshipId":{"type":["string","null"],"format":"uuid","description":"Third party subject: its relationship (lease, contract…) to a site; must not be ended."},"dueDate":{"type":["string","null"],"format":"date","description":"Default: today + the type's initial delay. A past date needs confirmPastDue."},"confirmPastDue":{"type":"boolean","default":false},"ownerUserId":{"type":["string","null"],"format":"uuid","description":"An owner, admin or manager seeing the site. Default: the site manager, else the portfolio manager, else nobody."},"ownerEmail":{"type":"string","format":"email","description":"Alternative to ownerUserId: the email of a member of the organization who can own it. Not both."},"priority":{"type":"string","enum":["low","normal","high","critical"],"default":"normal"},"direction":{"type":"string","enum":["inbound","outbound"],"default":"inbound","description":"inbound (collected from the subject, default) or outbound (produced and sent to it: subjectType must be party or organization)."},"customFields":{"type":"object","additionalProperties":true,"description":"Values of the custom fields of the requirement entity, by identifier. Required fields must be present."},"partyId":{"type":["string","null"],"format":"uuid","description":"Provider in charge of the evidence (inspection body, maintenance company…): a non-archived third party of the organization. Only for an inbound requirement whose subject is a site, unit, asset or the organization (a third-party subject provides its own evidence: 422 obl.providerPartySubject; outbound: 422 obl.providerOutbound). It then receives the requests, reminders and portal link; the subject does not change. null removes the provider."}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Requirement"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"An administrator is converting or editing the custom fields of these items (`ref.customFieldsLocked`, waited 3 s): nothing was written; try again after `Retry-After`. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/requirements/{id}":{"get":{"tags":["requirements"],"operationId":"GetRequirement","summary":"Get a requirement","security":[{"bearer":["read:requirements"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Requirement"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["requirements"],"operationId":"UpdateRequirement","summary":"Update a requirement","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:requirements"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Send dueDate (with reason) to change the due date, ownerUserId to reassign or clear the owner, customFields, partyId to entrust the requirement to a provider (null removes it), remindersPausedUntil, waived (with reason, optionally waivedUntil) to waive it or lift the waiver, and/or excluded (with reason) to close it as « does not apply » or reinstate it. excluded: false applies first, then the others in that order, excluded: true last; one refused (422) leaves the earlier ones applied. waived and excluded name a target state: already reached, nothing changes and nothing is recorded (a replay is harmless). A body with none of them is a 400 api.invalidBody. A closed requirement refuses the due date, the owner, the provider and the waiver (422 obl.closed).","properties":{"dueDate":{"type":"string","format":"date","description":"New due date, different from the current one. A past date needs confirmPastDue."},"reason":{"type":"string","minLength":10,"maxLength":1000,"description":"Required with dueDate, waived and excluded; kept in the history."},"confirmPastDue":{"type":"boolean","default":false},"ownerUserId":{"type":["string","null"],"format":"uuid","description":"An owner, admin or manager of the organization; null clears the owner."},"ownerEmail":{"type":"string","format":"email","description":"Alternative to ownerUserId (not both): the email of a member of the organization who can own it."},"customFields":{"type":"object","additionalProperties":true,"description":"Custom field values to change, by identifier; fields not sent keep their value. Allowed on a closed requirement."},"checkpointDone":{"type":"boolean","description":"Ticks (true) or unticks (false) the organization's own reminder step (Settings › Statuses and steps), as on the requirement page; read back as checkpointDoneAt. Nothing else changes (status, reminders). Allowed on a closed requirement; already in that state, nothing is recorded. The organization has no such step: 422 obl.checkpointDisabled."},"partyId":{"type":["string","null"],"format":"uuid","description":"Provider in charge of the evidence (inspection body, maintenance company…): a non-archived third party of the organization. Only for an inbound requirement whose subject is a site, unit, asset or the organization (a third-party subject provides its own evidence: 422 obl.providerPartySubject; outbound: 422 obl.providerOutbound). It then receives the requests, reminders and portal link; the subject does not change. null removes the provider."},"remindersPausedUntil":{"type":["string","null"],"format":"date","description":"Suspend the automatic reminders through this day (local time of the third party, at most one year ahead); null resumes. Read back in reminders.pausedUntil: the end of that day as an instant. A replay changes nothing."},"waived":{"type":"boolean","description":"true: waive it (status waived, reminders stop) until waivedUntil, or without end; false: lift the waiver (status recomputed). Requires reason, kept in the history under the key's name. When the organization requires a second approval, true records waiverRequest instead (status and reminders unchanged) until an owner or admin approves it — in the application, or with POST /requirements/{id}/decide-waiver by a write:reviews key of another owner or admin; a new call replaces the pending request, false withdraws it."},"waivedUntil":{"type":["string","null"],"format":"date","description":"With waived: true only: last day of the waiver (today or later, at most 5 years ahead); absent or null: no end."},"excluded":{"type":"boolean","description":"true: close it as « does not apply » (closedReason manual, closedNote = reason); false: reinstate a requirement closed that way (status recomputed), including one closed by undoing an import (its closedNote says so). It also reinstates a third party's own requirement closed with its last relationship (closedReason relationship_ended, no relationship). A requirement closed for another reason is refused with a code naming the way out (422): obl.closedWithRelationship (change the relationship's end date), obl.closedWithSubject (restore the archived element), obl.typeInactive (reactivate the type) — obl.notExcluded before 20 October 2026. Requires reason."},"handlingSetting":{"type":"string","enum":["inherit","platform","client"],"description":"« Calls and review » (assisted service; « Handled by » on the screens before October 2026): platform (the Vigilo team calls the third parties who do not answer and reviews their documents), client (the organization's team) or inherit (its compliance type's choice). A setting of the owner / admin: the key needs write:settings as well (403 api.insufficientScope, checked before anything applies). Applied after the other fields, before waived / excluded; the same value again records nothing. Refused in a self-service organization (422 org.notManaged: it reads client everywhere)."}},"anyOf":[{"required":["dueDate"]},{"required":["ownerUserId"]},{"required":["ownerEmail"]},{"required":["customFields"]},{"required":["checkpointDone"]},{"required":["partyId"]},{"required":["remindersPausedUntil"]},{"required":["waived"]},{"required":["excluded"]},{"required":["handlingSetting"]}],"dependentRequired":{"dueDate":["reason"],"waived":["reason"],"excluded":["reason"],"waivedUntil":["waived"]},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Requirement"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"An administrator is converting or editing the custom fields of these items (`ref.customFieldsLocked`, waited 3 s): nothing was written; try again after `Retry-After`. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/relationships":{"get":{"tags":["relationships"],"operationId":"ListRelationships","summary":"List relationships","security":[{"bearer":["read:parties"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"includeArchived","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"}},{"name":"updatedSince","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only the rows whose updatedAt is at or after this instant (ISO 8601 with Z or an offset). Incremental sync: send the time you started the previous sync minus a few minutes (a change being written at that moment may carry an earlier time), then deduplicate by id; add includeArchived=true to see the rows archived since. A party's updatedAt also moves when an official register's answer about it changes (registry); a document's when Vigilo replaces its uploaded bytes by the compressed copy (storedCopy)."},{"name":"partyId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"siteId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"unitId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","schema":{"type":"string","enum":["upcoming","active","ended"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Relationship"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["relationships"],"operationId":"CreateRelationship","summary":"Create a relationship","security":[{"bearer":["write:parties"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["partyId","relationType","startsOn"],"properties":{"partyId":{"type":"string","format":"uuid","description":"A non-archived third party of the organization."},"siteId":{"type":["string","null"],"format":"uuid","description":"The site; may be left out when unitId is given."},"unitId":{"type":["string","null"],"format":"uuid","description":"A unit of the site (its site is filled in; a different siteId answers 422 ref.unitSiteMismatch)."},"relationType":{"type":"string","enum":["lease","contract","assignment","maintenance","employment","other"]},"reference":{"type":["string","null"],"maxLength":60},"startsOn":{"type":"string","format":"date"},"endsOn":{"type":["string","null"],"format":"date","description":"An end date already passed closes the requirements of the relationship at once."}},"anyOf":[{"required":["siteId"]},{"required":["unitId"]}],"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Relationship"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/relationships/{id}":{"get":{"tags":["relationships"],"operationId":"GetRelationship","summary":"Get a relationship","security":[{"bearer":["read:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Relationship"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["relationships"],"operationId":"UpdateRelationship","summary":"Update a relationship","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Fields sent are changed, the others kept. endsOn ends the relationship: once the date has passed, its requirements are closed and no longer reminded (they reopen if the end date is removed or moved to the future). An archived relationship answers 422 ref.archived.","properties":{"relationType":{"type":"string","enum":["lease","contract","assignment","maintenance","employment","other"]},"reference":{"type":["string","null"],"maxLength":60},"startsOn":{"type":"string","format":"date"},"endsOn":{"type":["string","null"],"format":"date","description":"End date; null removes it."},"closeUnlinked":{"type":"boolean","default":false,"description":"With endsOn: also close the third party's own requirements tied to no relationship (one per party), as \"End the relationship\" does in the application. Only when no other relationship of the party runs after endsOn (422 ref.partyStillRelated otherwise, nothing written)."}},"minProperties":1,"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Relationship"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["relationships"],"operationId":"DeleteRelationship","summary":"Archive a relationship","description":"A relationship entered by mistake (wrong third party, site or unit), as on the screen: its requirements are closed (closedReason subject_archived: reminders stop). A contract that ends is ended with PATCH endsOn instead, which keeps it in the history. POST /relationships/{id}/restore brings it back. An archived relationship stays readable with includeArchived=true; archiving it again answers 204.","security":[{"bearer":["write:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Archived."},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/relationships/{id}/restore":{"post":{"tags":["relationships"],"operationId":"RestoreRelationship","summary":"Restore a relationship","description":"A relationship archived on the screen or by an import undone. One not ended also reopens the third party's own requirements closed with its last relationship. Under an archived third party, site or unit: restore it first. The requirements closed with it reopen (status recomputed). Not archived (a replay): the same answer. The journal records the restore under the key. No body.","security":[{"bearer":["write:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"responses":{"200":{"description":"Restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Relationship"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `ref.parentArchived` (what holds it is archived: restore that first), `aud.partyAlreadyErased` (an erased third party is never restored), `org.suspended`, `org.closed`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/contacts":{"get":{"tags":["contacts"],"operationId":"ListContacts","summary":"List contacts","security":[{"bearer":["read:parties"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"includeArchived","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"}},{"name":"updatedSince","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only the rows whose updatedAt is at or after this instant (ISO 8601 with Z or an offset). Incremental sync: send the time you started the previous sync minus a few minutes (a change being written at that moment may carry an earlier time), then deduplicate by id; add includeArchived=true to see the rows archived since. A party's updatedAt also moves when an official register's answer about it changes (registry); a document's when Vigilo replaces its uploaded bytes by the compressed copy (storedCopy)."},{"name":"partyId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"email","in":"query","schema":{"type":"string","maxLength":254,"description":"Exact address, case ignored: the contact your system knows."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["contacts"],"operationId":"CreateContact","summary":"Create a contact","security":[{"bearer":["write:parties"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["partyId"],"description":"At least a first or last name (ref.contactNameRequired) and an email or a phone (ref.contactChannelRequired). The first contact added becomes primary, in place of the one made from the third party's email.","properties":{"partyId":{"type":"string","format":"uuid","description":"A non-archived third party of the organization: unknown, 422 validation.invalid with fieldErrors.partyId; archived, 422 ref.parentArchived."},"firstName":{"type":["string","null"],"maxLength":100},"lastName":{"type":["string","null"],"maxLength":100},"email":{"type":["string","null"],"format":"email","maxLength":254,"description":"An active contact of the same third party already has this address (case ignored): 422 ref.duplicateContactEmail with existingId. A changed address revokes the portal links sent to the previous one."},"phone":{"type":["string","null"],"maxLength":40,"description":"Stored in E.164 (country of the third party)."},"jobTitle":{"type":["string","null"],"maxLength":120},"locale":{"type":["string","null"],"enum":["en","fr","de","es","it","pt","nl","pl","sv","da","nb","fi","cs","ro","hu","el","tr","ja","zh","ar"],"description":"Default: the third party's language."},"isPrimary":{"type":"boolean","description":"true: becomes the primary contact (the previous one loses the flag). The primary contact cannot be set to false: make another one primary."},"receivesRequests":{"type":"boolean","description":"false: no longer receives the requests and reminders; the portal links already sent to it stop working.","default":true}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/contacts/{id}":{"get":{"tags":["contacts"],"operationId":"GetContact","summary":"Get a contact","security":[{"bearer":["read:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["contacts"],"operationId":"UpdateContact","summary":"Update a contact","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"An archived contact answers 422 ref.archived.","properties":{"firstName":{"type":["string","null"],"maxLength":100},"lastName":{"type":["string","null"],"maxLength":100},"email":{"type":["string","null"],"format":"email","maxLength":254,"description":"An active contact of the same third party already has this address (case ignored): 422 ref.duplicateContactEmail with existingId. A changed address revokes the portal links sent to the previous one."},"phone":{"type":["string","null"],"maxLength":40,"description":"Stored in E.164 (country of the third party)."},"jobTitle":{"type":["string","null"],"maxLength":120},"locale":{"type":["string","null"],"enum":["en","fr","de","es","it","pt","nl","pl","sv","da","nb","fi","cs","ro","hu","el","tr","ja","zh","ar"],"description":"Default: the third party's language."},"isPrimary":{"type":"boolean","description":"true: becomes the primary contact (the previous one loses the flag). The primary contact cannot be set to false: make another one primary."},"receivesRequests":{"type":"boolean","description":"false: no longer receives the requests and reminders; the portal links already sent to it stop working."}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["contacts"],"operationId":"DeleteContact","summary":"Archive a contact","description":"As on the screen: the contact no longer receives anything, its portal links stop working, and the oldest remaining contact becomes primary; POST /contacts/{id}/restore brings it back. An archived contact stays readable with includeArchived=true; archiving it again answers 204.","security":[{"bearer":["write:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Archived."},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/contacts/{id}/restore":{"post":{"tags":["contacts"],"operationId":"RestoreContact","summary":"Restore a contact","description":"A contact archived by mistake: it receives the requests again; it stays primary unless its third party has another primary contact now. Its portal links stay revoked. Under an archived third party: restore the party first. The requirements closed with it reopen (status recomputed). Not archived (a replay): the same answer. The journal records the restore under the key. No body.","security":[{"bearer":["write:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"responses":{"200":{"description":"Restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `ref.parentArchived` (what holds it is archived: restore that first), `aud.partyAlreadyErased` (an erased third party is never restored), `org.suspended`, `org.closed`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/contacts/{id}/revert-email-change":{"post":{"tags":["contacts"],"operationId":"RevertContactEmailChange","summary":"Undo the address change a contact made on its portal","description":"A contact may change its own address from its portal (applied once it types the code sent to the new address; the members following the party are told). If the link was in the wrong hands, put the previous address back within 30 days, as « Undo this change » on the party page: the contact (and an individual third party's email) gets previousEmail back and every portal link of the contact stops working, the one used for the change included — issue a new one (POST /portal-links). The history names the key. The answer is the contact.","security":[{"bearer":["write:parties"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["changeId"],"properties":{"changeId":{"type":"string","format":"uuid","description":"portalEmailChange.id as you read it (GET /contacts/{id}): no longer undoable, 409 prt.emailChangeNotRevertible."}},"additionalProperties":false}}}},"responses":{"200":{"description":"The contact with its previous address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"No longer undoable (`prt.emailChangeNotRevertible`): already undone, the address changed again, the contact archived, or more than 30 days old. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `validation.invalid` with `fieldErrors` (changeId: `validation.required`, or `ref.invalidReference` for an id that is not a change of this contact), `org.suspended`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/findings":{"get":{"tags":["findings"],"operationId":"ListFindings","summary":"List findings","security":[{"bearer":["read:requirements"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"includeArchived","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"},"description":"true: also the findings of archived requirements. A finding leaves the list when its requirement is archived, without its updatedAt moving: follow the requirement (archivedAt)."},{"name":"updatedSince","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only the findings whose updatedAt is at or after this instant (ISO 8601 with Z or an offset): raised, assignee or correction date changed, status changed. Send the time you started the previous sync minus a few minutes, then deduplicate by id."},{"name":"requirementId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"siteId","in":"query","schema":{"type":"string","format":"uuid","description":"The site of the finding's requirement."}},{"name":"partyId","in":"query","schema":{"type":"string","format":"uuid","description":"The third party of the finding's requirement."}},{"name":"status","in":"query","schema":{"type":"string","description":"One or several of open, in_progress, resolved, verified, wont_fix, comma-separated (status=open,in_progress: the open findings)."}},{"name":"severity","in":"query","schema":{"type":"string","description":"One or several of critical, major, minor, observation, comma-separated."}},{"name":"overdue","in":"query","schema":{"type":"string","enum":["true","false"],"description":"true: still open and past dueDate."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Finding"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["findings"],"operationId":"CreateFinding","summary":"Create a finding","security":[{"bearer":["write:requirements"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["requirementId","title","severity"],"description":"An open finding of the same requirement with the same title (case and spacing ignored) answers 422 fnd.duplicateOpen with existingId: a POST replayed after a lost answer finds the finding instead of doubling it. Two findings of one report differ by their title (place, equipment). A requirement holds 200 open findings at most (422 fnd.tooManyOpen).","properties":{"requirementId":{"type":"string","format":"uuid","description":"A requirement of the organization, neither archived nor closed: unknown or archived, 422 validation.invalid with fieldErrors.requirementId; closed, 422 obl.closed."},"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":["string","null"],"maxLength":2000},"severity":{"type":"string","enum":["critical","major","minor","observation"],"description":"critical blocks the requirement's compliance when its compliance type says so (isBlocked)."},"assigneeUserId":{"type":["string","null"],"format":"uuid","description":"The member who corrects it: an owner, admin or manager seeing the requirement's site (obl.ownerOutOfScope otherwise); null: nobody."},"assigneeEmail":{"type":"string","format":"email","description":"Alternative to assigneeUserId (not both): the email of a member of the organization."},"dueDate":{"type":["string","null"],"format":"date","description":"Correct before this day (10 years ahead at most); null: no date."},"sharedWithParty":{"type":"boolean","description":"true: listed on the third party's portal and announced to it by email (default false: internal). An inbound requirement with a third party only (422 fnd.noParty). false withdraws it from the portal."}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Finding"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/findings/{id}":{"get":{"tags":["findings"],"operationId":"GetFinding","summary":"Get a finding","security":[{"bearer":["read:requirements"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Finding"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["findings"],"operationId":"UpdateFinding","summary":"Update a finding","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:requirements"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Send title, description, severity, dueDate, assigneeUserId (or assigneeEmail) and/or sharedWithParty while the finding is open (422 fnd.notOpen afterwards), and/or status. The finding of an archived requirement stays readable and answers 422 ref.parentArchived. A key records the progress of the correction: in_progress (taken in charge) and resolved (with resolutionNote), whoever the assignee is; verifying, reopening and discarding (verified, wont_fix) are a member's decisions, on the screen. The same status sent again (same resolutionNote) answers 200 and writes nothing; any other move answers 422 fnd.invalidTransition. Sent together, the fields apply before the status; a status refused leaves them applied.","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":["string","null"],"maxLength":2000},"severity":{"type":"string","enum":["critical","major","minor","observation"],"description":"Raised by the key; lowered (critical → major…) by an owner or administrator on the screen only (403 auth.lowerSeverity): it may unblock the requirement, as accepting a finding without correction."},"assigneeUserId":{"type":["string","null"],"format":"uuid","description":"The member who corrects it: an owner, admin or manager seeing the requirement's site (obl.ownerOutOfScope otherwise); null: nobody."},"assigneeEmail":{"type":"string","format":"email","description":"Alternative to assigneeUserId (not both): the email of a member of the organization."},"dueDate":{"type":["string","null"],"format":"date","description":"Correct before this day (10 years ahead at most); null: no date."},"sharedWithParty":{"type":"boolean","description":"true: listed on the third party's portal and announced to it by email (default false: internal). An inbound requirement with a third party only (422 fnd.noParty). false withdraws it from the portal."},"status":{"type":"string","enum":["in_progress","resolved"],"description":"in_progress: from open. resolved: from open or in_progress, with resolutionNote; a member other than the one who created the key then verifies it."},"resolutionNote":{"type":"string","minLength":3,"maxLength":2000,"description":"What was done. Required with status: resolved, refused without it."},"proofFileIds":{"type":"array","maxItems":5,"items":{"type":"string","format":"uuid"},"description":"With status: resolved only. The proof of the correction (intervention report, photo): files this key uploaded for the finding's requirement (POST /files?requirementId=, scope write:submissions), not yet used. Another file, or one already used: 422 sub.fileNotFound."}},"anyOf":[{"required":["title"]},{"required":["description"]},{"required":["severity"]},{"required":["dueDate"]},{"required":["assigneeUserId"]},{"required":["assigneeEmail"]},{"required":["sharedWithParty"]},{"required":["status"]}],"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Finding"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/requirements/{id}/decide-waiver":{"post":{"tags":["requirements"],"operationId":"DecideWaiverRequest","summary":"Approve or refuse a waiver request","description":"When the organization requires a second approval of waivers (Settings › Statuses and steps), a waiver asked by a member or a key waits in waiverRequest until another owner or admin decides. A key decides in the name of the member who created it, as on the requirement page: approve (the requirement is waived as asked; an end date already past answers 422 obl.waiverEndPast: refuse it and ask again) or refuse with a reason (the requester is told). The creator must be owner or admin and not the requester — for a request sent by a key, its creator (409 obl.ownWaiverRequest). The audit journal names the key and the member it decided for (onBehalfOfUserId). The answer is the requirement.","security":[{"bearer":["write:reviews"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["action","requestedAt"],"properties":{"action":{"type":"string","enum":["approve","refuse"],"description":"approve: the waiver applies as asked (reason, end date), the requester kept as the one who waived it. refuse: nothing changes but the request is gone."},"reason":{"type":"string","minLength":10,"maxLength":1000,"description":"Required with refuse (told to the requester, kept in the history); not sent with approve."},"requestedAt":{"type":"string","format":"date-time","description":"waiverRequest.requestedAt as you read it (GET /requirements/{id}): the decision applies to that request only; replaced or withdrawn since, 409 obl.noWaiverRequest (read it again)."}},"additionalProperties":false}}}},"responses":{"200":{"description":"The requirement after the decision","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Requirement"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`); the key's creator may no longer review (`auth.keyCreatorCannotReview`) or is not owner or admin (`auth.keyCreatorNotAdmin`); a requirement with health data is decided on the screen only (`auth.healthDataOnScreen`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"No pending request, or it changed since requestedAt (`obl.noWaiverRequest`: read the requirement again); the creator asked for it (`obl.ownWaiverRequest`). A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `validation.invalid` with `fieldErrors` (action, reason: `validation.required` when empty, `validation.tooShort` when shorter than 10 characters, requestedAt: `validation.required`), `obl.closed` (approve on a closed requirement), `obl.waiverEndPast`, `org.suspended`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/findings/{id}/decide":{"post":{"tags":["findings"],"operationId":"DecideFinding","summary":"Verify, send back, accept or reopen a finding","description":"The decisions a member takes on a finding, by a key in the name of the member who created it, with their rights (role capped at manager, their scope), as on the requirement page: verify a resolution, send it back, accept a finding without correction (an owner or admin decision), reopen a verified or accepted one. The requirement's status follows (a finding that blocks compliance blocks it again when reopened); a third party that answered from its portal is told why by email when its answer is sent back or the finding reopened. The answer is the finding.","security":[{"bearer":["write:reviews"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["verify","reject","wont_fix","reopen"],"description":"verify: a resolved finding is checked (never by whoever resolved it: 422 fnd.selfVerification). reject: a resolution sent back (in_progress). wont_fix: an open finding accepted without correction (the creator must be owner or admin). reopen: a verified or wont_fix finding open again."},"note":{"type":"string","maxLength":2000,"description":"The reason: required for wont_fix (10 characters at least) and reopen (3), and for reject when the third party answered (it reads it on its portal and by email)."}},"additionalProperties":false}}}},"responses":{"200":{"description":"The finding after the decision","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Finding"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`); the key's creator may no longer review (`auth.keyCreatorCannotReview`), or is no longer owner or admin for wont_fix (`auth.keyCreatorNotAdmin`); a requirement with health data is decided on the screen only (`auth.healthDataOnScreen`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `validation.invalid` with `fieldErrors` (action, note: `validation.tooShort`), `fnd.invalidTransition` (the finding is not in a status this action applies to: read it again), `fnd.selfVerification` (the creator, or a key of theirs, resolved it), `fnd.tooManyOpen` (reopen: the requirement already holds 200 open findings), `org.suspended`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/reminders":{"get":{"tags":["reminders"],"operationId":"ListReminders","summary":"List reminders","security":[{"bearer":["read:reminders"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"requirementId","in":"query","schema":{"type":"string","format":"uuid","description":"The emails that ask for this requirement."}},{"name":"partyId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","schema":{"type":"string","description":"One or several of queued, sent, failed, comma-separated."}},{"name":"trigger","in":"query","schema":{"type":"string","description":"One or several of reminder_step, manual, system, comma-separated."}},{"name":"queuedSince","in":"query","schema":{"type":"string","format":"date-time","description":"Only the emails queued at or after this instant (ISO 8601 with Z or an offset)."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Reminder"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["reminders"],"operationId":"CreateReminder","summary":"Remind now","description":"« Remind now »: one email to each contact of the requirement's third party that receives the requests, now, in the organization's name, even while its reminders are suspended; the planned reminders continue from it. At most one reminder a day for a requirement through the API.","security":[{"bearer":["write:reminders"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["requirementId"],"properties":{"requirementId":{"type":"string","format":"uuid","description":"The requirement to remind its third party of."}},"additionalProperties":false}}}},"responses":{"201":{"description":"The emails sent","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Reminder"}}}}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A reminder already left today, local time of the third party (`rmd.alreadyRemindedToday`, with `lastRemindedAt`): see GET /api/v1/reminders?requirementId=. Or the third party already received twice the organization's weekly cap of reminder emails (manual and automatic) in the last 7 days (`rmd.capExceeded`, 6 by default): only an owner or admin sends another one, from the requirement's page, with a reason. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Unknown requirement (`validation.invalid`, `requirementId`), nobody to remind (`rmd.noParty`), a requirement that is compliant, under review, waived, closed or sent by the organization (`rmd.notRemindable`), no contact that receives the requests (`rmd.noRecipient`), or the mail server refused the email (`rmd.sendFailed`: the email is listed as failed). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/reminders/{id}":{"get":{"tags":["reminders"],"operationId":"GetReminder","summary":"Get a reminder","security":[{"bearer":["read:reminders"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reminder"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/messages":{"get":{"tags":["messages"],"operationId":"ListMessages","summary":"List messages","security":[{"bearer":["read:reminders"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"requirementId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"partyId","in":"query","schema":{"type":"string","format":"uuid","description":"The messages on the requirements followed with this third party."}},{"name":"from","in":"query","schema":{"type":"string","enum":["party","organization"]}},{"name":"createdSince","in":"query","schema":{"type":"string","format":"date-time","description":"Only the messages written at or after this instant (ISO 8601 with Z or an offset)."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Message"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["messages"],"operationId":"CreateMessage","summary":"Write to the third party","description":"Writes on the requirement's thread as the organization, as a member does on the screen: each contact of the third party that receives the requests gets an email with a portal link limited to this requirement (the email does not carry the text). The third party reads the organization's name, the members the key's name. The same text by the same key on the requirement within 24 hours answers 409 api.alreadySent with existingId (no second email); 10 messages an hour at most per key and requirement.","security":[{"bearer":["write:reminders"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["requirementId","body"],"properties":{"requirementId":{"type":"string","format":"uuid","description":"The requirement to write about to its third party."},"body":{"type":"string","minLength":1,"maxLength":2000,"description":"The text; the email tells the third party to read it on its portal (it never carries the text)."}},"additionalProperties":false}}}},"responses":{"201":{"description":"The message written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The same text was already written by this key on the requirement within 24 hours (`api.alreadySent`, with `existingId`). A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Unknown requirement (`validation.invalid`, `requirementId`), a requirement without third party (`prt.noParty`) or without a contact that receives the requests (`prt.noContact`), a text empty or over 2,000 characters (`body`), more than 10 messages this hour (`prt.messageRateLimited`). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/messages/{id}":{"get":{"tags":["messages"],"operationId":"GetMessage","summary":"Get a message","security":[{"bearer":["read:reminders"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/portal-links":{"get":{"tags":["portal-links"],"operationId":"ListPortalLinks","summary":"List portal links","security":[{"bearer":["read:reminders"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"partyId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"contactId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"active","in":"query","schema":{"type":"string","enum":["true","false"],"description":"true: the links that open the portal now; false: revoked or expired ones, or of an archived third party or contact."}},{"name":"delegated","in":"query","schema":{"type":"string","enum":["true","false"],"description":"true: only the links a contact forwarded from its own (delegatedFromId); false or absent: only the organization's links."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PortalLink"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["portal-links"],"operationId":"CreatePortalLink","summary":"Create a portal link","description":"A link for your own tool to send (purchase order, welcome email, supplier portal): it opens the third party's portal to the contact, without an account, for 30 days. The url is given in this answer only. The key's links are its own: the same contact and scope again answers 409 api.alreadySent with existingId, regenerate: true revokes the key's link and gives a new one; the links of Vigilo's emails and of the members are never touched. A requirement that asks for a code (sensitive type) sends it to the contact's email, never to the key. 20 active links at most per key and third party. Revoking the key revokes its links (key_revoked).","security":[{"bearer":["write:portal-links"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"partyId or requirementIds, not both.","properties":{"partyId":{"type":"string","format":"uuid","description":"A link to every open requirement of this third party (all_open), read at each opening."},"requirementIds":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":50,"description":"A link to these open requirements only, all of the same third party."},"contactId":{"type":"string","format":"uuid","description":"The contact of the third party the link is for; by default the one the screen chooses: a contact who receives the requests (the primary one, else the oldest), else the primary contact."},"regenerate":{"type":"boolean","description":"true: revokes this key's active link for the same contact and scope and gives a new one (the links of the emails stay valid)."}},"additionalProperties":false}}}},"responses":{"201":{"description":"The link, with its url","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalLink"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"This key already holds an active link for this contact and scope (`api.alreadySent`, with `existingId`): its url cannot be read again, send regenerate: true. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Unknown third party, requirement or contact, or of another organization (`validation.invalid`, field named), third party or contact archived (`ref.archived`), a requirement closed, archived or sent by the organization (`api.requirementNotOpen`), requirements of several third parties (`api.severalParties`), a contact without email for a requirement that asks for a code (`prt.otpNoEmail`), no contact nor email for the third party (`prt.noContact`), 20 active links of the key on the third party (`api.tooManyLinks`). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/portal-links/{id}":{"get":{"tags":["portal-links"],"operationId":"GetPortalLink","summary":"Get a portal link","security":[{"bearer":["read:reminders"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortalLink"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["portal-links"],"operationId":"DeletePortalLink","summary":"Revoke a portal link","description":"The link stops opening the portal at once, whoever issued it (a member, an API key or an email of Vigilo), and so do the links the third party forwarded from it. A forwarded link (delegated=true: a mistyped address, a broker no longer in charge) is revoked alone. A revoked or expired link answers 204 too. The next request or reminder email carries a new link.","security":[{"bearer":["write:portal-links"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Revoked."},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/compliance-types":{"get":{"tags":["compliance-types"],"operationId":"ListComplianceTypes","summary":"List compliance types","security":[{"bearer":["read:requirements"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"includeInactive","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"},"description":"true: also the deactivated types."},{"name":"code","in":"query","schema":{"type":"string","maxLength":60,"description":"Case ignored."}},{"name":"subjectType","in":"query","schema":{"type":"string","enum":["party","site","unit","asset","organization"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ComplianceType"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/compliance-types/{id}":{"get":{"tags":["compliance-types"],"operationId":"GetComplianceType","summary":"Get a compliance type","security":[{"bearer":["read:requirements"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComplianceType"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["compliance-types"],"operationId":"UpdateComplianceType","summary":"Update a compliance type","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:settings"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"The switches of the type's page. PATCH: send at least one of isActive, handling, remindersEnabled, reminderLevel (400 api.invalidBody otherwise). Every value, and the refusals below (a type not published, a self-service organization), are checked before anything is written; the same value again records nothing. POST /compliance-types/{id}/preview with the same body tells what it would do (an empty body reads the counters).","properties":{"isActive":{"type":"boolean","description":"false deactivates the type: no new requirement can use it, its rules stop creating; its open requirements are kept (followed and reminded) unless closeRequirements is true. true reactivates it: the requirements its deactivation closed come back when their subject and lease are still followed, and its active rules are evaluated. A type not published yet: 422 obl.typeNotPublished."},"closeRequirements":{"type":"boolean","description":"With isActive false only (400 api.invalidBody otherwise): true closes its open requirements (closedReason type_deactivated, reminders stop) when the call deactivates the type; a reactivation reopens them. On a type already deactivated the call changes nothing, as a replay does."},"remindersEnabled":{"type":"boolean","description":"false: no automatic reminder for its requirements (manual ones stay possible); true: they follow the calendar again."},"reminderLevel":{"type":["string","null"],"enum":["gentle","standard","firm",null],"description":"gentle, standard or firm; null: back to the organization's calendar for its evidence kind."},"handling":{"type":"string","enum":["platform","client"],"description":"« Calls and review » of its requirements that have no choice of their own: platform (the Vigilo team) or client (the organization's team). The same value again records nothing. Refused in a self-service organization (422 org.notManaged: it reads client everywhere)."}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComplianceType"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/compliance-types/{id}/preview":{"post":{"tags":["compliance-types"],"operationId":"PreviewComplianceTypeUpdate","summary":"Preview the activation or deactivation of a compliance type","description":"The body of PATCH /compliance-types/{id}, checked the same way: the counters of the type page's dialog (open requirements, those the call would close or reopen, active rules); nothing is written. An empty body reads the counters.","security":[{"bearer":["write:settings"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","description":"The switches of the type's page. PATCH: send at least one of isActive, handling, remindersEnabled, reminderLevel (400 api.invalidBody otherwise). Every value, and the refusals below (a type not published, a self-service organization), are checked before anything is written; the same value again records nothing. POST /compliance-types/{id}/preview with the same body tells what it would do (an empty body reads the counters).","properties":{"isActive":{"type":"boolean","description":"false deactivates the type: no new requirement can use it, its rules stop creating; its open requirements are kept (followed and reminded) unless closeRequirements is true. true reactivates it: the requirements its deactivation closed come back when their subject and lease are still followed, and its active rules are evaluated. A type not published yet: 422 obl.typeNotPublished."},"closeRequirements":{"type":"boolean","description":"With isActive false only (400 api.invalidBody otherwise): true closes its open requirements (closedReason type_deactivated, reminders stop) when the call deactivates the type; a reactivation reopens them. On a type already deactivated the call changes nothing, as a replay does."},"remindersEnabled":{"type":"boolean","description":"false: no automatic reminder for its requirements (manual ones stay possible); true: they follow the calendar again."},"reminderLevel":{"type":["string","null"],"enum":["gentle","standard","firm",null],"description":"gentle, standard or firm; null: back to the organization's calendar for its evidence kind."},"handling":{"type":"string","enum":["platform","client"],"description":"« Calls and review » of its requirements that have no choice of their own: platform (the Vigilo team) or client (the organization's team). The same value again records nothing. Refused in a self-service organization (422 org.notManaged: it reads client everywhere)."}},"additionalProperties":false}}}},"responses":{"200":{"description":"What the write would do; nothing was written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComplianceTypePreview"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/settings":{"get":{"tags":["settings"],"operationId":"GetSettings","summary":"Get the lists and delays","description":"Settings › Lists and delays: the site types and equipment kinds the organization added to the delivered ones, and the default delays of a new compliance type; Settings › Third parties: partyIdentifiers.","security":[{"bearer":["read:settings"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Settings"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["settings"],"operationId":"UpdateSettings","summary":"Update the lists and delays","description":"The fields sent are changed, the others kept; a list sent replaces the stored one. Audited as organization.settings_updated (section lists, or parties for partyIdentifiers) under the key's name.","security":[{"bearer":["write:settings"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"The fields sent are changed, the others kept.","properties":{"siteTypes":{"type":"array","maxItems":50,"items":{"type":"string","minLength":1,"maxLength":60},"description":"Site types the organization added to the delivered ones, shown as typed (no comma). Sent: replaces the whole list (send it back with the new value). Twice the same value, or a delivered one (its code or its name in any language of Vigilo, case and accents ignored): 422 set.listDuplicate; a value already saved before Vigilo delivered the same word stays accepted. A value removed while an active site or asset still carries it, or a rule or a compliance type names it: 422 set.siteTypeInUse / set.assetKindInUse / set.listValueInRule / set.listValueInType with the value and the count."},"assetKinds":{"type":"array","maxItems":50,"items":{"type":"string","minLength":1,"maxLength":60},"description":"Equipment kinds the organization added to the delivered ones, shown as typed (no comma). Sent: replaces the whole list (send it back with the new value). Twice the same value, or a delivered one (its code or its name in any language of Vigilo, case and accents ignored): 422 set.listDuplicate; a value already saved before Vigilo delivered the same word stays accepted. A value removed while an active site or asset still carries it, or a rule or a compliance type names it: 422 set.siteTypeInUse / set.assetKindInUse / set.listValueInRule / set.listValueInType with the value and the count."},"initialDueDays":{"type":"integer","minimum":0,"maximum":365,"description":"Days given to provide the first document, for a compliance type activated or created from now on (each type keeps its own afterwards). Default 30."},"expiringSoonDays":{"type":"integer","minimum":0,"maximum":180,"description":"Days before expiry a requirement turns « expiring soon », for a new type. Default 30."},"graceDays":{"type":"integer","minimum":0,"maximum":90,"description":"Days after the due date before a requirement turns overdue, for a new type. Default 0."},"partyIdentifiers":{"type":"object","additionalProperties":false,"description":"Settings › Third parties: rules applied when a third party is created or changed (screens, import, this API). Only a change is checked: a party recorded before keeps its other edits. Fields sent are changed, the others kept.","properties":{"registryRecheckMonths":{"type":"integer","enum":[0,1,3,6,12],"description":"Months between two periodic checks of the parties' identifiers at the official registers (Sirene, VIES): 0 never, 1, 3, 6 (default) or 12. The check runs nightly on active companies with a running relationship or an open requirement, 100 parties a day per organization; a company found closed or a VAT number no longer confirmed notifies the party's manager (else the owners and admins) and shows in each party's registry. Any other value is refused with 422."},"registrationRequired":{"type":"boolean","description":"A company needs its registrationNumber (individuals are exempt): a company created without one, or a number emptied, is refused with 422 ref.registrationNumberRequired. Default false."},"rejectInvalid":{"type":"boolean","description":"An invalid registrationNumber (checked in FR: SIREN, SIRET, RNA; GB: company number; any non-empty value elsewhere) or vatNumber (EU format, and the check digits of FR, AT, BE, DE, DK, EE, EL, ES, FI, HR, HU, IT, LU, MT, NL, PL, PT, RO, SE, SI, SK; elsewhere two letters and a number) is refused with 422 ref.registrationNumberInvalid / ref.vatNumberInvalid instead of a warning. Default false."}}}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Settings"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/custom-fields":{"get":{"tags":["settings"],"operationId":"ListCustomFields","summary":"List custom fields","security":[{"bearer":["read:settings"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"includeArchived","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"},"description":"true: also the archived fields."},{"name":"entity","in":"query","schema":{"type":"string","enum":["site","party","requirement"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CustomField"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["settings"],"operationId":"CreateCustomField","summary":"Create a custom field","security":[{"bearer":["write:settings"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["entity","key","fieldType","label"],"properties":{"entity":{"type":"string","enum":["site","party","requirement"]},"key":{"type":"string","pattern":"^[a-z][a-z0-9_]{1,39}$","description":"Unique per entity; the key of the value in customFields."},"fieldType":{"type":"string","enum":["text","long_text","number","money","date","boolean","select","multi_select","email","phone","url"]},"label":{"type":"string","minLength":1,"maxLength":100,"description":"In the organization's language (the other languages of the label are kept)."},"required":{"type":"boolean"},"options":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":100},"description":"select / multi_select only: the values, case-insensitively unique. Sent: replaces the list."}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomField"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/custom-fields/{id}":{"get":{"tags":["settings"],"operationId":"GetCustomField","summary":"Get a custom field","security":[{"bearer":["read:settings"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomField"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["settings"],"operationId":"UpdateCustomField","summary":"Update a custom field","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:settings"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"archived: true archives (no longer shown nor asked, values kept), false restores; send it alone (400 api.invalidBody otherwise). 50 active fields per entity at most (422 ref.customFieldLimit).","properties":{"label":{"type":"string","minLength":1,"maxLength":100,"description":"In the organization's language (the other languages of the label are kept)."},"required":{"type":"boolean"},"options":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":100},"description":"select / multi_select only: the values, case-insensitively unique. Sent: replaces the list."},"archived":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomField"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/rules":{"get":{"tags":["settings"],"operationId":"ListRules","summary":"List assignment rules","security":[{"bearer":["read:settings"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"complianceTypeId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"isActive","in":"query","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Rule"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["settings"],"operationId":"CreateRule","summary":"Create an assignment rule","security":[{"bearer":["write:settings"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"description":"complianceTypeId or complianceTypeCode, not both. Active (isActive true): evaluated in the same call, as on the screen.","properties":{"name":{"type":"string","minLength":2,"maxLength":120,"description":"Unique among the organization's rules, case ignored (422 rul.duplicateName)."},"complianceTypeId":{"type":"string","format":"uuid","description":"An active compliance type of the organization."},"complianceTypeCode":{"type":"string","maxLength":60,"description":"Alternative to complianceTypeId: the type's code, case ignored."},"selector":{"type":"object","additionalProperties":false,"properties":{"partyRoles":{"type":"array","items":{"type":"string","enum":["tenant","supplier","subcontractor","contractor","service_provider","inspection_body","broker","employee","owner","other"]}},"relationTypes":{"type":"array","items":{"type":"string","enum":["lease","contract","assignment","maintenance","employment","other"]}},"portfolioIds":{"type":"array","items":{"type":"string","format":"uuid"}},"siteIds":{"type":"array","items":{"type":"string","format":"uuid"}},"siteTypes":{"type":"array","items":{"type":"string","maxLength":60},"description":"Delivered codes or values added in GET /settings; another value: 422 validation.optionInvalid."},"unitTypes":{"type":"array","items":{"type":"string","enum":["apartment","house","shop","office","storage","parking","warehouse","other"]}},"assetKinds":{"type":"array","items":{"type":"string","maxLength":60},"description":"Delivered codes or values added in GET /settings; another value: 422 validation.optionInvalid."},"tagsAny":{"type":"array","items":{"type":"string","maxLength":40},"description":"At least one of these tags."},"countries":{"type":"array","items":{"type":"string"},"description":"ISO 3166-1 alpha-2 countries or ISO 3166-2 regions (GB-SCT, US-CA…)."},"customFields":{"type":"array","maxItems":5,"description":"Conditions on a custom field (GET /settings/custom-fields): the third party's for a third-party rule, the site's for a site, unit or equipment rule. All must match. Usable types and operators: select and multi_select → any_of (values: some of the field's options); number and money → at_least / at_most (number, bound included; money in the organization's currency); boolean → is_true / is_false (false: unticked or never filled in). Another type, an archived or unknown key, an option not in the list: 422 naming the condition (selector.customFields.0.values…). In a PATCH, a selector without customFields keeps the stored conditions; [] removes them.","items":{"type":"object","additionalProperties":false,"required":["key","op"],"properties":{"key":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,62}$","description":"Key of the custom field."},"op":{"type":"string","enum":["any_of","at_least","at_most","is_true","is_false"]},"values":{"type":"array","maxItems":100,"items":{"type":"string","maxLength":100},"description":"any_of: options of the field (OR); ignored by the other operators (answered empty)."},"number":{"type":["number","null"],"description":"at_least / at_most: the bound; ignored by the other operators (answered null)."}}}},"perRelationship":{"type":["boolean","null"],"description":"Third-party rules: one requirement per lease or contract (true, the default) or one per third party (false); null: the default."}},"description":"Which subjects of the type's subject type the rule covers: every criterion sent must match (AND), any value of a list (OR); none: every subject. The criteria a subject type takes are those of the screen (a site rule has no partyRoles…); another one answers 422 naming it. Sent in a PATCH: replaces all the criteria (send the ones to keep), except customFields: left out, the stored conditions stay; [] removes them."},"duePolicy":{"type":"object","additionalProperties":false,"required":["from"],"properties":{"from":{"type":"string","enum":["creation","relationship_start","fixed_date"],"description":"creation: the day the requirement is created; relationship_start: the start of the lease or contract (third-party rules); fixed_date: fixedDate."},"offsetDays":{"type":["integer","null"],"minimum":-365,"maximum":365,"description":"Days added to the start; null with creation: the delay of the type's version."},"fixedDate":{"type":["string","null"],"format":"date"}}},"isActive":{"type":"boolean","description":"Default false: created inactive, activated later."},"holdRequests":{"type":"boolean","description":"true: the requirements this save creates keep their reminders paused (you write to the third parties first). Not stored on the rule."}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rule"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Another rule of the same compliance type is being changed (`rul.busy`, waited 3 s): nothing was written; try again after `Retry-After`. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/rules/preview":{"post":{"tags":["settings"],"operationId":"PreviewRuleCreate","summary":"Preview the rule a creation would make","description":"The body of POST /rules, checked the same way (but the name, unique at the creation): the preview of the rule editor — the subjects covered, the requirements its evaluation would create, the third parties written to first; nothing is written. Not active (isActive false or absent): skippedReason rule_inactive, toCreate is what an activation would create.","security":[{"bearer":["write:settings"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"description":"complianceTypeId or complianceTypeCode, not both. Active (isActive true): evaluated in the same call, as on the screen.","properties":{"name":{"type":"string","minLength":2,"maxLength":120,"description":"Unique among the organization's rules, case ignored (422 rul.duplicateName)."},"complianceTypeId":{"type":"string","format":"uuid","description":"An active compliance type of the organization."},"complianceTypeCode":{"type":"string","maxLength":60,"description":"Alternative to complianceTypeId: the type's code, case ignored."},"selector":{"type":"object","additionalProperties":false,"properties":{"partyRoles":{"type":"array","items":{"type":"string","enum":["tenant","supplier","subcontractor","contractor","service_provider","inspection_body","broker","employee","owner","other"]}},"relationTypes":{"type":"array","items":{"type":"string","enum":["lease","contract","assignment","maintenance","employment","other"]}},"portfolioIds":{"type":"array","items":{"type":"string","format":"uuid"}},"siteIds":{"type":"array","items":{"type":"string","format":"uuid"}},"siteTypes":{"type":"array","items":{"type":"string","maxLength":60},"description":"Delivered codes or values added in GET /settings; another value: 422 validation.optionInvalid."},"unitTypes":{"type":"array","items":{"type":"string","enum":["apartment","house","shop","office","storage","parking","warehouse","other"]}},"assetKinds":{"type":"array","items":{"type":"string","maxLength":60},"description":"Delivered codes or values added in GET /settings; another value: 422 validation.optionInvalid."},"tagsAny":{"type":"array","items":{"type":"string","maxLength":40},"description":"At least one of these tags."},"countries":{"type":"array","items":{"type":"string"},"description":"ISO 3166-1 alpha-2 countries or ISO 3166-2 regions (GB-SCT, US-CA…)."},"customFields":{"type":"array","maxItems":5,"description":"Conditions on a custom field (GET /settings/custom-fields): the third party's for a third-party rule, the site's for a site, unit or equipment rule. All must match. Usable types and operators: select and multi_select → any_of (values: some of the field's options); number and money → at_least / at_most (number, bound included; money in the organization's currency); boolean → is_true / is_false (false: unticked or never filled in). Another type, an archived or unknown key, an option not in the list: 422 naming the condition (selector.customFields.0.values…). In a PATCH, a selector without customFields keeps the stored conditions; [] removes them.","items":{"type":"object","additionalProperties":false,"required":["key","op"],"properties":{"key":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,62}$","description":"Key of the custom field."},"op":{"type":"string","enum":["any_of","at_least","at_most","is_true","is_false"]},"values":{"type":"array","maxItems":100,"items":{"type":"string","maxLength":100},"description":"any_of: options of the field (OR); ignored by the other operators (answered empty)."},"number":{"type":["number","null"],"description":"at_least / at_most: the bound; ignored by the other operators (answered null)."}}}},"perRelationship":{"type":["boolean","null"],"description":"Third-party rules: one requirement per lease or contract (true, the default) or one per third party (false); null: the default."}},"description":"Which subjects of the type's subject type the rule covers: every criterion sent must match (AND), any value of a list (OR); none: every subject. The criteria a subject type takes are those of the screen (a site rule has no partyRoles…); another one answers 422 naming it. Sent in a PATCH: replaces all the criteria (send the ones to keep), except customFields: left out, the stored conditions stay; [] removes them."},"duePolicy":{"type":"object","additionalProperties":false,"required":["from"],"properties":{"from":{"type":"string","enum":["creation","relationship_start","fixed_date"],"description":"creation: the day the requirement is created; relationship_start: the start of the lease or contract (third-party rules); fixed_date: fixedDate."},"offsetDays":{"type":["integer","null"],"minimum":-365,"maximum":365,"description":"Days added to the start; null with creation: the delay of the type's version."},"fixedDate":{"type":["string","null"],"format":"date"}}},"isActive":{"type":"boolean","description":"Default false: created inactive, activated later."},"holdRequests":{"type":"boolean","description":"true: the requirements this save creates keep their reminders paused (you write to the third parties first). Not stored on the rule."}},"additionalProperties":false}}}},"responses":{"200":{"description":"What the write would do; nothing was written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RulePreview"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/rules/{id}/preview":{"post":{"tags":["settings"],"operationId":"PreviewRuleUpdate","summary":"Preview what a rule would create after a change","description":"The body of PATCH /rules/{id}, checked the same way; an empty body previews the rule as stored. Before activating a rule ({ \"isActive\": true }): how many requirements it would create and which third parties would be written to first; nothing is written.","security":[{"bearer":["write:settings"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","description":"The fields sent are changed. isActive false keeps every requirement the rule created, flagged out of rule; saving an active rule evaluates it again.","properties":{"name":{"type":"string","minLength":2,"maxLength":120,"description":"Unique among the organization's rules, case ignored (422 rul.duplicateName)."},"selector":{"type":"object","additionalProperties":false,"properties":{"partyRoles":{"type":"array","items":{"type":"string","enum":["tenant","supplier","subcontractor","contractor","service_provider","inspection_body","broker","employee","owner","other"]}},"relationTypes":{"type":"array","items":{"type":"string","enum":["lease","contract","assignment","maintenance","employment","other"]}},"portfolioIds":{"type":"array","items":{"type":"string","format":"uuid"}},"siteIds":{"type":"array","items":{"type":"string","format":"uuid"}},"siteTypes":{"type":"array","items":{"type":"string","maxLength":60},"description":"Delivered codes or values added in GET /settings; another value: 422 validation.optionInvalid."},"unitTypes":{"type":"array","items":{"type":"string","enum":["apartment","house","shop","office","storage","parking","warehouse","other"]}},"assetKinds":{"type":"array","items":{"type":"string","maxLength":60},"description":"Delivered codes or values added in GET /settings; another value: 422 validation.optionInvalid."},"tagsAny":{"type":"array","items":{"type":"string","maxLength":40},"description":"At least one of these tags."},"countries":{"type":"array","items":{"type":"string"},"description":"ISO 3166-1 alpha-2 countries or ISO 3166-2 regions (GB-SCT, US-CA…)."},"customFields":{"type":"array","maxItems":5,"description":"Conditions on a custom field (GET /settings/custom-fields): the third party's for a third-party rule, the site's for a site, unit or equipment rule. All must match. Usable types and operators: select and multi_select → any_of (values: some of the field's options); number and money → at_least / at_most (number, bound included; money in the organization's currency); boolean → is_true / is_false (false: unticked or never filled in). Another type, an archived or unknown key, an option not in the list: 422 naming the condition (selector.customFields.0.values…). In a PATCH, a selector without customFields keeps the stored conditions; [] removes them.","items":{"type":"object","additionalProperties":false,"required":["key","op"],"properties":{"key":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,62}$","description":"Key of the custom field."},"op":{"type":"string","enum":["any_of","at_least","at_most","is_true","is_false"]},"values":{"type":"array","maxItems":100,"items":{"type":"string","maxLength":100},"description":"any_of: options of the field (OR); ignored by the other operators (answered empty)."},"number":{"type":["number","null"],"description":"at_least / at_most: the bound; ignored by the other operators (answered null)."}}}},"perRelationship":{"type":["boolean","null"],"description":"Third-party rules: one requirement per lease or contract (true, the default) or one per third party (false); null: the default."}},"description":"Which subjects of the type's subject type the rule covers: every criterion sent must match (AND), any value of a list (OR); none: every subject. The criteria a subject type takes are those of the screen (a site rule has no partyRoles…); another one answers 422 naming it. Sent in a PATCH: replaces all the criteria (send the ones to keep), except customFields: left out, the stored conditions stay; [] removes them."},"duePolicy":{"type":"object","additionalProperties":false,"required":["from"],"properties":{"from":{"type":"string","enum":["creation","relationship_start","fixed_date"],"description":"creation: the day the requirement is created; relationship_start: the start of the lease or contract (third-party rules); fixed_date: fixedDate."},"offsetDays":{"type":["integer","null"],"minimum":-365,"maximum":365,"description":"Days added to the start; null with creation: the delay of the type's version."},"fixedDate":{"type":["string","null"],"format":"date"}}},"isActive":{"type":"boolean","description":"true activates (evaluates), false deactivates."},"holdRequests":{"type":"boolean","description":"true: the requirements this save creates keep their reminders paused (you write to the third parties first). Not stored on the rule."}},"additionalProperties":false}}}},"responses":{"200":{"description":"What the write would do; nothing was written","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RulePreview"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/rules/{id}":{"get":{"tags":["settings"],"operationId":"GetRule","summary":"Get an assignment rule","security":[{"bearer":["read:settings"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rule"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["settings"],"operationId":"UpdateRule","summary":"Update an assignment rule","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:settings"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"The fields sent are changed. isActive false keeps every requirement the rule created, flagged out of rule; saving an active rule evaluates it again.","properties":{"name":{"type":"string","minLength":2,"maxLength":120,"description":"Unique among the organization's rules, case ignored (422 rul.duplicateName)."},"selector":{"type":"object","additionalProperties":false,"properties":{"partyRoles":{"type":"array","items":{"type":"string","enum":["tenant","supplier","subcontractor","contractor","service_provider","inspection_body","broker","employee","owner","other"]}},"relationTypes":{"type":"array","items":{"type":"string","enum":["lease","contract","assignment","maintenance","employment","other"]}},"portfolioIds":{"type":"array","items":{"type":"string","format":"uuid"}},"siteIds":{"type":"array","items":{"type":"string","format":"uuid"}},"siteTypes":{"type":"array","items":{"type":"string","maxLength":60},"description":"Delivered codes or values added in GET /settings; another value: 422 validation.optionInvalid."},"unitTypes":{"type":"array","items":{"type":"string","enum":["apartment","house","shop","office","storage","parking","warehouse","other"]}},"assetKinds":{"type":"array","items":{"type":"string","maxLength":60},"description":"Delivered codes or values added in GET /settings; another value: 422 validation.optionInvalid."},"tagsAny":{"type":"array","items":{"type":"string","maxLength":40},"description":"At least one of these tags."},"countries":{"type":"array","items":{"type":"string"},"description":"ISO 3166-1 alpha-2 countries or ISO 3166-2 regions (GB-SCT, US-CA…)."},"customFields":{"type":"array","maxItems":5,"description":"Conditions on a custom field (GET /settings/custom-fields): the third party's for a third-party rule, the site's for a site, unit or equipment rule. All must match. Usable types and operators: select and multi_select → any_of (values: some of the field's options); number and money → at_least / at_most (number, bound included; money in the organization's currency); boolean → is_true / is_false (false: unticked or never filled in). Another type, an archived or unknown key, an option not in the list: 422 naming the condition (selector.customFields.0.values…). In a PATCH, a selector without customFields keeps the stored conditions; [] removes them.","items":{"type":"object","additionalProperties":false,"required":["key","op"],"properties":{"key":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,62}$","description":"Key of the custom field."},"op":{"type":"string","enum":["any_of","at_least","at_most","is_true","is_false"]},"values":{"type":"array","maxItems":100,"items":{"type":"string","maxLength":100},"description":"any_of: options of the field (OR); ignored by the other operators (answered empty)."},"number":{"type":["number","null"],"description":"at_least / at_most: the bound; ignored by the other operators (answered null)."}}}},"perRelationship":{"type":["boolean","null"],"description":"Third-party rules: one requirement per lease or contract (true, the default) or one per third party (false); null: the default."}},"description":"Which subjects of the type's subject type the rule covers: every criterion sent must match (AND), any value of a list (OR); none: every subject. The criteria a subject type takes are those of the screen (a site rule has no partyRoles…); another one answers 422 naming it. Sent in a PATCH: replaces all the criteria (send the ones to keep), except customFields: left out, the stored conditions stay; [] removes them."},"duePolicy":{"type":"object","additionalProperties":false,"required":["from"],"properties":{"from":{"type":"string","enum":["creation","relationship_start","fixed_date"],"description":"creation: the day the requirement is created; relationship_start: the start of the lease or contract (third-party rules); fixed_date: fixedDate."},"offsetDays":{"type":["integer","null"],"minimum":-365,"maximum":365,"description":"Days added to the start; null with creation: the delay of the type's version."},"fixedDate":{"type":["string","null"],"format":"date"}}},"isActive":{"type":"boolean","description":"true activates (evaluates), false deactivates."},"holdRequests":{"type":"boolean","description":"true: the requirements this save creates keep their reminders paused (you write to the third parties first). Not stored on the rule."}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Rule"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Another rule of the same compliance type is being changed (`rul.busy`, waited 3 s): nothing was written; try again after `Retry-After`. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/members":{"get":{"tags":["members"],"operationId":"ListMembers","summary":"List members","security":[{"bearer":["read:members"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"role","in":"query","schema":{"type":"string","enum":["owner","admin","manager","viewer"]}},{"name":"email","in":"query","schema":{"type":"string","format":"email","description":"The member with this address (case ignored)."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Member"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/members/{id}":{"get":{"tags":["members"],"operationId":"GetMember","summary":"Get a member","security":[{"bearer":["read:members"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Member"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["members"],"operationId":"UpdateMember","summary":"Update a member","description":"The fields sent are changed, the others kept; null clears an optional field.","security":[{"bearer":["write:members"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"A manager or a viewer: the fields sent are changed, the others kept. portfolioIds or siteIds without scopeAll restrict the scope to them; scopeAll: true opens the whole organization. Another role than viewer clears accessUntil. absence plans or changes a manager's absence (null ends it; a viewer: 422 org.absenceNotAllowed); the deputy must be an owner, admin or manager whose scope covers the member's (422 org.invalidDeputy) and not away on these days (422 org.deputyAbsent). All or nothing: a refused field leaves every field as it was. An owner or an admin: 403 auth.adminOnScreen.","properties":{"role":{"type":"string","enum":["manager","viewer"]},"scopeAll":{"type":"boolean","description":"true: the whole organization. false: only the portfolios and sites listed (managers and viewers)."},"portfolioIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":200,"description":"Portfolios reached, with all their sites (scopeAll false)."},"siteIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500,"description":"Sites reached one by one (scopeAll false)."},"accessUntil":{"type":["string","null"],"format":"date","description":"Last day of a temporary access, in the organization's time zone (viewers only, an auditor for instance; at most 365 days ahead); null: no end."},"absence":{"type":["object","null"],"required":["from","until","deputyMemberId"],"properties":{"from":{"type":"string","format":"date","description":"First day of the absence, in the organization's time zone (today at the earliest when written, at most 366 days ahead)."},"until":{"type":"string","format":"date","description":"Last day, included (at most 186 days from the first)."},"deputyMemberId":{"type":"string","format":"uuid"}},"additionalProperties":false}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Member"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["members"],"operationId":"DeleteMember","summary":"Remove a member","description":"A manager or a viewer, as on the screen: their access ends at their next request, the requirements they owned lose their owner, their open tasks are unassigned, the admins are told. With replacementMemberId, the open and closed requirements they owned, the sites and portfolios they managed and their open corrective actions go to that member first, within the replacement's scope (what lies outside loses its owner); the replacement is told. An owner or an admin: 403 auth.adminOnScreen.","security":[{"bearer":["write:members"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"replacementMemberId","in":"query","schema":{"type":"string","format":"uuid","description":"Member (id from GET /members) who takes over: an owner, admin or manager other than the removed member; otherwise 422 with replacementMemberId: org.invalidReplacement."}}],"responses":{"204":{"description":"Removed."},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/invitations":{"get":{"tags":["members"],"operationId":"ListInvitations","summary":"List invitations","security":[{"bearer":["read:members"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"email","in":"query","schema":{"type":"string","format":"email","description":"The pending invitation of this address (case ignored)."}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Invitation"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["members"],"operationId":"CreateInvitation","summary":"Create an invitation","security":[{"bearer":["write:members"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","role"],"description":"Invites a manager or a viewer: an email with a link valid 7 days goes to the address, naming the member who created the key. Without portfolioIds or siteIds, the whole organization. 100 pending invitations at most (422 org.tooManyInvitations), 3 invitation emails per address and hour (422 org.invitationRateLimited); an address already a member (org.alreadyMember) or already invited (org.invitationPending) is refused.","properties":{"email":{"type":"string","format":"email","maxLength":254},"role":{"type":"string","enum":["manager","viewer"],"description":"admin is given on the screen only (403 auth.adminOnScreen)."},"scopeAll":{"type":"boolean","description":"true: the whole organization. false: only the portfolios and sites listed (managers and viewers)."},"portfolioIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":200,"description":"Portfolios reached, with all their sites (scopeAll false)."},"siteIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500,"description":"Sites reached one by one (scopeAll false)."},"accessUntil":{"type":["string","null"],"format":"date","description":"Last day of a temporary access, in the organization's time zone (viewers only, an auditor for instance; at most 365 days ahead); null: no end."},"locale":{"type":"string","enum":["en","fr","de","es","it","pt","nl","pl","sv","da","nb","fi","cs","ro","hu","el","tr","ja","zh","ar"],"description":"Language of the email; the organization's by default."}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invitation"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/invitations/{id}":{"get":{"tags":["members"],"operationId":"GetInvitation","summary":"Get an invitation","security":[{"bearer":["read:members"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invitation"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["members"],"operationId":"DeleteInvitation","summary":"Revoke an invitation","description":"Its link stops working at once. An accepted invitation is a member (DELETE /members/{id}); an invitation to an administrator: 403 auth.adminOnScreen.","security":[{"bearer":["write:members"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Revoked."},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/submissions":{"get":{"tags":["submissions"],"operationId":"ListSubmissions","summary":"List submitted documents","security":[{"bearer":["read:submissions"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"Cursor: the `nextCursor` of the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"includeArchived","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"}},{"name":"updatedSince","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only the rows whose updatedAt is at or after this instant (ISO 8601 with Z or an offset). Incremental sync: send the time you started the previous sync minus a few minutes (a change being written at that moment may carry an earlier time), then deduplicate by id; add includeArchived=true to see the rows archived since. A party's updatedAt also moves when an official register's answer about it changes (registry); a document's when Vigilo replaces its uploaded bytes by the compressed copy (storedCopy)."},{"name":"requirementId","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"partyId","in":"query","schema":{"type":"string","format":"uuid","description":"The third party that provides the evidence (the requirement's partyId)."}},{"name":"status","in":"query","style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","enum":["pending_review","in_review","approved","rejected","superseded","withdrawn"]},"minItems":1},"description":"One status, or several separated by commas (status=approved,rejected)."},{"name":"include","in":"query","style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","enum":["review"]},"minItems":1},"description":"review: add the review trace (reviewComment, firstReviewedAt, firstReviewedBy, firstReviewComment, checklist). Your team's comments: do not pass them on to the third party."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Submission"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["submissions"],"operationId":"CreateSubmission","summary":"Send a document","description":"Second step: the document for a requirement, with the files uploaded by POST /files and the values of its fields. It waits for a member's review (status pending_review; approved at once if the type is approved automatically and nothing needs a human). A document waiting and not held by a reviewer is replaced; held: 409 sub.pendingReserved. The same call repeated within 10 minutes (same fileIds and values; without files, same values from the same key) answers the first document. The answer is the document created.","security":[{"bearer":["write:submissions"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["requirementId"],"properties":{"requirementId":{"type":"string","format":"uuid","description":"The open requirement the document answers (GET /requirements). Unknown, archived or of another organization: 422 with fieldErrors.requirementId; closed: 422 sub.requirementClosed."},"fileIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":20,"uniqueItems":true,"default":[],"description":"The ids answered by POST /files for this requirement with this key, not attached yet (kept 24 hours). At least the version's minimum number of files."},"fieldValues":{"type":"object","additionalProperties":true,"default":{},"description":"Values by field key: the fields of the requirement's type version (GET /compliance-types/{id}, currentVersion.fields); required ones must be present. Dates as YYYY-MM-DD; an amount as a number, its currency under <key>.currency when the field lets the submitter choose it. Refused: 422 validation.invalid with fieldErrors.<key>."},"notes":{"type":["string","null"],"maxLength":2000}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A reviewer holds the document waiting for this requirement (`sub.pendingReserved`): try again later. Or these files were already sent with other values (`api.alreadySent`, the document in `existingId`): upload the files again to send a corrected document. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `validation.invalid` with `fieldErrors` (fieldValues.<key>, requirementId; a date printed on the document later than tomorrow: `sub.printedDateInFuture`; a next due date before the check it follows: `sub.dueBeforeCheck`), `sub.minFiles`, `sub.fileNotFound` (a file id unknown, already used, expired, or uploaded by another key or for another requirement), `sub.requirementClosed`, `org.suspended`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/submissions/{id}":{"get":{"tags":["submissions"],"operationId":"GetSubmission","summary":"Get a submitted document","security":[{"bearer":["read:submissions"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"include","in":"query","style":"form","explode":false,"schema":{"type":"array","items":{"type":"string","enum":["review"]},"minItems":1},"description":"review: add the review trace (reviewComment, firstReviewedAt, firstReviewedBy, firstReviewComment, checklist). Your team's comments: do not pass them on to the third party."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/submissions/{id}/approve":{"post":{"tags":["submissions"],"operationId":"ApproveSubmission","summary":"Approve a document","description":"The key decides in the name of the member who created it, with their rights: their role (capped at manager) and their scope, as on the review screen (fields corrected, checklist, comment for an expired document). The document is approved and the requirement covered; for a four-eyes type (reviewMode double) the first approval leaves it in_review until another member approves it — the key counts as its creator, never twice (409 sub.sameReviewer). With the organization's « whoever submits does not approve » rule, a document the creator sent for the third party, or sent by a key or a portal link of theirs, is refused (409 sub.ownDeposit, sub.ownKey, sub.ownLink). The answer is the document with include=review.","security":[{"bearer":["write:reviews"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["lockVersion"],"properties":{"lockVersion":{"type":"integer","minimum":0,"description":"The document's lockVersion as you read it (GET /submissions/{id}): changed since, 409 sub.concurrentUpdate (read it again, then decide)."},"fieldValues":{"type":"object","additionalProperties":true,"default":{},"description":"Your corrections only, by field key of the document's version (complianceTypeVersionId); the other values stay as sent. Same formats as POST /submissions. A key that is no field of that version: 422 with fieldErrors.fieldValues.<key>: api.unknownField."},"checklist":{"type":"object","additionalProperties":{"type":"boolean"},"default":{},"description":"The checklist of the document's version, item key -> checked. A blocking item left unchecked: 422 sub.checklistIncomplete; an unknown key: 422 api.unknownField."},"comment":{"type":["string","null"],"maxLength":1000,"description":"Internal, never shown to the third party (reviewComment). Required to approve a document already expired (422 sub.commentRequired)."}},"additionalProperties":false}}}},"responses":{"200":{"description":"The document after the decision","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`); the key's creator may no longer review — viewer, removed, blocked (`auth.keyCreatorCannotReview`: create a new key); a type with health data is decided on the screen only (`auth.healthDataOnScreen`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The document changed since you read lockVersion (`sub.concurrentUpdate`), a member has it open (`sub.reservedByOther`: try again after Retry-After, the end of the member's reservation), it is already decided (`sub.notReviewable`), or the creator may not approve it: they approved its first step (`sub.sameReviewer`) or sent it (`sub.ownDeposit`, `sub.ownKey`, `sub.ownLink`). A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `validation.invalid` with `fieldErrors` (lockVersion, fieldValues.<key> — `api.unknownField` for a key of no field of the document's version —, checklist.<key>, comment), `sub.checklistIncomplete` (a blocking item unchecked), `sub.commentRequired` (the document has expired: say why you approve it), `sub.requirementClosed` (closed since it was sent), `org.suspended`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/submissions/{id}/reject":{"post":{"tags":["submissions"],"operationId":"RejectSubmission","summary":"Reject a document","description":"The key decides in the name of the member who created it, with their role (capped at manager) and their scope, as on the review screen. The third party is told the reason and comment by email with a link to send a new document; at the second step of a four-eyes review the member who approved the first step is told. Rejecting stays possible where approving is not (own deposit, same reviewer). The answer is the document with include=review.","security":[{"bearer":["write:reviews"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["lockVersion","reasonCode"],"properties":{"lockVersion":{"type":"integer","minimum":0,"description":"The document's lockVersion as you read it: changed since, 409 sub.concurrentUpdate."},"reasonCode":{"type":"string","enum":["unreadable","expired","wrong_document","wrong_holder","insufficient_coverage","missing_pages","other"],"description":"Why, as the third party reads it (rejectionReasonCode)."},"comment":{"type":["string","null"],"maxLength":1000,"description":"Shown to the third party with the reason (rejectionComment); required with reasonCode other."},"internalNote":{"type":["string","null"],"maxLength":1000,"description":"Kept for the organization, never shown to the third party nor returned by the API."}},"additionalProperties":false}}}},"responses":{"200":{"description":"The document after the decision","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`); the key's creator may no longer review (`auth.keyCreatorCannotReview`); a type with health data is decided on the screen only (`auth.healthDataOnScreen`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The document changed since you read lockVersion (`sub.concurrentUpdate`), a member has it open (`sub.reservedByOther`: try again after Retry-After), or it is already decided (`sub.notReviewable`). A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `validation.invalid` with `fieldErrors` (lockVersion, reasonCode, comment: required with reasonCode other), `sub.requirementClosed` (closed since it was sent), `org.suspended`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/submissions/{id}/revoke":{"post":{"tags":["submissions"],"operationId":"RevokeApproval","summary":"Revoke an approval","description":"An approval given by mistake, or a document found false afterwards: the document becomes rejected (rejectionReasonCode other, the reason as rejectionComment, which the third party reads on its portal; no email) and the requirement is recomputed from the approvals left (none left: no coverage, its status by its due date), as with « Revoke approval » on the review screen. An owner or admin decision: the key acts in the name of the member who created it, while they are owner or admin. The approval stays in the history. To review it again: POST /submissions/{id}/return-to-review. Revoked already with the same reason (a replay after a lost answer): the same answer, nothing recorded twice. The answer is the document with include=review.","security":[{"bearer":["write:reviews"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","minLength":1,"maxLength":1000,"description":"Why the approval is revoked: kept in the history, read back as rejectionComment (rejectionReasonCode other) and shown to the third party on its portal."}},"additionalProperties":false}}}},"responses":{"200":{"description":"The document after the revocation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`); the key's creator may no longer review (`auth.keyCreatorCannotReview`) or is no longer owner or admin (`auth.keyCreatorNotAdmin`); a type with health data is decided on the screen only (`auth.healthDataOnScreen`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The document is not approved (`sub.notApproved`: rejected, or revoked with another reason), or it changed meanwhile (`sub.concurrentUpdate`). A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `validation.invalid` with `fieldErrors` (reason), `org.suspended`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/submissions/{id}/return-to-review":{"post":{"tags":["submissions"],"operationId":"ReturnSubmissionToReview","summary":"Put a rejected document back to review","description":"A document rejected by mistake, or whose approval was revoked, waits for a decision again (pending_review; in_review at the second step of a four-eyes review when it was there), as with « Review again » on the review screen, without asking the third party for the same file: then approve or reject it. The requirement follows it. Refused once a newer document was sent (review that one), when its files were erased, or when the requirement is closed. The third party is not told; the decision taken next is. The rejection stays in the history. The body is optional: send the lockVersion you read so that a newer decision is never undone unseen. Back to review already (a replay after a lost answer, whatever its lockVersion): the same answer, nothing recorded twice. The answer is the document with include=review.","security":[{"bearer":["write:reviews"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"lockVersion":{"type":"integer","minimum":0,"description":"The document's lockVersion as you read it (optional): changed since — rejected again, for instance —, 409 sub.concurrentUpdate."}},"additionalProperties":false}}}},"responses":{"200":{"description":"The document waiting for review","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`); the key's creator may no longer review (`auth.keyCreatorCannotReview`); a type with health data is decided on the screen only (`auth.healthDataOnScreen`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The document is not rejected (`sub.notRejected`: approved, or waiting for its first decision), a newer document was sent (`sub.newerDeposit`), its files were erased (`sub.filesErased`), or it changed since you read lockVersion (`sub.concurrentUpdate`). A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `validation.invalid` with `fieldErrors` (lockVersion), `sub.requirementClosed` (the requirement is closed), `org.suspended`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/submissions/{id}/withdraw":{"post":{"tags":["submissions"],"operationId":"WithdrawSubmission","summary":"Withdraw a document not decided yet","description":"A wrong file, a document sent twice: the document stops counting and the requirement returns to its previous state (the last decided document, or waiting for evidence), as with « Withdraw » on the review screen. Any document waiting for review may be withdrawn (sent by a member, a key or the third party; the third party is not told — reject it to ask for another one). The document it had replaced (a document waiting for review is replaced by a newer one) comes back to review. The document stays readable with status withdrawn, and the journal records who withdrew it. No body. Already withdrawn: the same answer. A decided document cannot be withdrawn: an approval is revoked (POST /submissions/{id}/revoke).","security":[{"bearer":["write:submissions"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"eraseFiles","in":"query","schema":{"type":"boolean","default":false},"description":"true: its files are erased too (a wrong file holding another person's data): the bytes are deleted, the file keeps its fingerprint and reads « erased ». Refused under a legal hold of the organization (422 sub.eraseUnderHold)."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"responses":{"200":{"description":"The document withdrawn","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Submission"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A member has it open (`sub.reservedByOther`: try again later), or it is already decided (`sub.notWithdrawable`). A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `sub.requirementClosed` (the requirement is closed), `sub.eraseUnderHold` (eraseFiles under a legal hold: withdraw without it), `validation.invalid` (eraseFiles neither true nor false), `org.suspended`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/imports/workbook":{"get":{"tags":["imports"],"operationId":"GetStarterWorkbook","summary":"Get the starter workbook","description":"The template of the starter workbook (.xlsx), the screen's « Complete file »: Read me, one sheet per kind in the order of import (portfolios, sites, units, third parties, equipment, requirements, team, party contacts), Lists; headers marked * are mandatory, list cells offer their values, lengths are checked by Excel; the organization's custom fields and active compliance types are included.","security":[{"bearer":["write:import"]}],"parameters":[{"name":"example","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"},"description":"true: with example rows (replace or delete them: an example row left as it is is refused)."},{"name":"locale","in":"query","schema":{"type":"string","enum":["en","fr","de","es","it","pt","nl","pl","sv","da","nb","fi","cs","ro","hu","el","tr","ja","zh","ar"],"default":"en"},"description":"Language of the sheet names, headers, lists and Read me."}],"responses":{"200":{"description":"The workbook.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["imports"],"operationId":"ImportStarterWorkbook","summary":"Check or import the starter workbook","description":"The body is the .xlsx itself (raw bytes, no multipart; 10 MB and 5 000 rows at most). By default a check: the whole report, nothing written. commit=true imports all or nothing: one error anywhere and nothing is written (422 with the report). A workbook sent while another of the organization is being checked or imported answers 409 `api.importRunning`, or waits for it before writing: send the next one when the answer arrives. A known portfolio (same name or code), site (same code), unit (same site and reference), equipment (same site and reference) or third party (same registration number) is not created again (existing, and differing when a filled cell differs from its record); update=true applies those cells to the known portfolios, sites, units and equipment (updated; an empty cell keeps the value, third parties are never updated). A code of an archived site or unit is an error (imp.archivedKnown: restore it first); an external reference already used is an error (ref.duplicateExternalRef). Give each site, unit and equipment its code and each third party its externalRef (your tool's id) or its registration number: the same workbook sent again (a retry after a lost answer) then writes nothing twice, its report saying what is already there. Sheets and headers are recognized in the template's language, in the locale given, or in English. The Team sheet invites one person per row (email, role manager / viewer, portfolios and sites by code or name, access until for a viewer, invitation language) in the name of the member who created the key; it needs the write:members scope too (403 api.insufficientScope otherwise) and its emails leave once the workbook is imported (invitations: sent, failed). An address already a member or invited is existing; administrators are invited on the screen (auth.adminOnScreen).","security":[{"bearer":["write:import"]}],"parameters":[{"name":"commit","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"},"description":"true: import (all or nothing). false: check only."},{"name":"update","in":"query","schema":{"type":"string","enum":["true","false"],"default":"false"},"description":"true: known portfolios, sites, units, equipment and party contacts take the file's filled cells (rows updated); false: they are left as they are (existing)."},{"name":"locale","in":"query","schema":{"type":"string","enum":["en","fr","de","es","it","pt","nl","pl","sv","da","nb","fi","cs","ro","hu","el","tr","ja","zh","ar"],"default":"en"},"description":"Language of a workbook made without the template (sheet names, headers, list values); the template's own language is always recognized."},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"The report: a check, or the import done (committed true).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkbookReport"}}}},"400":{"description":"Invalid or unknown parameter (`api.invalidParameter`, `api.unknownParameter`), or the workbook sent as a form (`api.invalidBody`: send the bytes themselves). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`): write:import, or write:members when the Team sheet has rows.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A workbook of the organization is being checked or imported (`api.importRunning`): send the next one when its answer arrives. An administrator is converting or editing the custom fields of these items (`ref.customFieldsLocked`, waited 3 s): nothing was written; try again after `Retry-After`. A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"`imp.workbookHasErrors`: commit=true and the workbook has errors, nothing written; the body is { error, report }, the report as the check gives it. Or the file itself is refused (body { error }): `imp.workbookXlsxOnly` (not an .xlsx), `imp.tooLarge`, `imp.empty`, `imp.tooManyRows`, `imp.sheetTooManyRows`, `imp.tooManyCells` (more than 300 000 cells or 50 000 rows in its sheets, formatted ones included), `imp.unreadable`, `org.suspended`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"$ref":"#/components/schemas/Error"},"report":{"$ref":"#/components/schemas/WorkbookReport"}}}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`), or the server is reading too many files at once (`rate.limited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/imports":{"get":{"tags":["imports"],"operationId":"ListImports","summary":"List the last imports","description":"The 10 latest imports of the organization that wrote something (the starter workbook through the API or the screen, the screen's imports of one kind), the latest first, as Import › Recent imports shows them.","security":[{"bearer":["write:import"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Import"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/imports/{id}":{"get":{"tags":["imports"],"operationId":"GetImport","summary":"Get an import","description":"One import, and while it may be undone what an undo would reach (undoImpact): read it before POST /imports/{id}/undo.","security":[{"bearer":["write:import"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportDetail"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/imports/{id}/undo":{"post":{"tags":["imports"],"operationId":"UndoImport","summary":"Undo an import","description":"The wrong file, columns mixed up, an old list loaded: what the import created is archived, each element as an archive by hand (its requirements closed, reminders stopped, portal links revoked; restorable one by one with POST /{collection}/{id}/restore), and the requirements of its Requirements sheet on elements that existed before are closed (reason « Import undone »). Codes and references of what it created are released (suffix ~…): the corrected file loads at once. Never undone: the rows updated, the existing third parties (only the relationships the import created are archived), the invitations of the Team sheet, the emails sent. Within 30 days, once; the key's creator must be owner or admin, as on the screen. Already undone (a replay, or on the screen): the same answer. No body. The journal records import.undone and each archive under the key.","security":[{"bearer":["write:import"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"responses":{"200":{"description":"Undone: undoneAt and undoCounts set.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportDetail"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`), or the key's creator is no longer owner or admin (`auth.keyCreatorNotAdmin`: undo it on the screen, or create a new key).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `imp.undoExpired` (more than 30 days), `imp.undoEmpty` (it created nothing: a Team sheet alone), `org.suspended`, `org.closed`. The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/files":{"post":{"tags":["submissions"],"operationId":"UploadFile","summary":"Upload a file","description":"First step of sending a document: the body is the file itself (raw bytes, any Content-Type; no multipart). Checked like an upload on the screen: the type read from the content must be one the requirement's type accepts and match the name's extension, the size within its limit, a PDF not encrypted, no virus. The file is kept 24 hours for this key; send it with POST /submissions, or delete it (DELETE /files/{id}). 20 files at most wait for a requirement.","security":[{"bearer":["write:submissions"]}],"parameters":[{"name":"requirementId","in":"query","required":true,"schema":{"type":"string","format":"uuid"},"description":"The open requirement the document is for."},{"name":"name","in":"query","required":true,"schema":{"type":"string","maxLength":255},"description":"File name with its extension (attestation.pdf)."}],"requestBody":{"required":true,"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"Uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadedFile"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused: `file.typeNotAllowed` (the message says the file cannot be opened when a document extension holds no document: damaged file, saved web page), `file.typeMismatch` (extension and content differ), `file.tooLarge`, `file.tooManyPixels` (an image beyond 50 megapixels), `file.empty`, `file.incomplete` (fewer bytes arrived than the Content-Length announced: send the file again), `file.encryptedPdf`, `file.infected`, `sub.tooManyFiles` (20 files waiting), `sub.requirementClosed`, `validation.invalid` (requirementId unknown or name missing: fieldErrors), `org.suspended`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The antivirus or the file storage cannot be reached right now (`file.scanUnavailable`, `file.storeUnavailable`): try again after the seconds of Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/submissions/{id}/files/{fileId}":{"get":{"tags":["submissions"],"operationId":"GetSubmissionFileContent","summary":"Get the content of a file","description":"The bytes of a file of the document, as uploaded (Content-Type recorded at upload, Repr-Digest with its SHA-256). Every download is recorded in the audit journal (file.downloaded).","security":[{"bearer":["read:submissions"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"fileId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The content of the file.","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"The content was erased (GDPR erasure, or the document withdrawn with eraseFiles: `api.fileErased`); the document still lists the file with its fingerprint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The file storage cannot be reached right now (`file.storeUnavailable`): try again after the seconds of Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/files/{id}":{"delete":{"tags":["submissions"],"operationId":"DeleteFile","summary":"Delete an uploaded file","description":"A file this key uploaded and has not sent yet (a wrong file): deleted at once instead of after 24 hours. Sent, or uploaded by another key: 404.","security":[{"bearer":["write:submissions"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Deleted."},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhooks":{"get":{"tags":["webhooks"],"operationId":"ListWebhooks","summary":"List the webhook endpoints of this key","description":"The endpoints this key subscribed, never those created in the application or by another key.","security":[{"bearer":["write:webhooks"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["webhooks"],"operationId":"CreateWebhook","summary":"Subscribe an endpoint to events","description":"REST hook: 201 with Location, the address to DELETE when the subscription ends. The signing secret is in the answer, this once. The endpoint lives with the key: revoking the key disables it at once, an expired key disables it at the next event. 25 endpoints at most per organization (422 webhook.tooMany).","security":[{"bearer":["write:webhooks"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri","maxLength":2000,"description":"https address on a public host that receives the events (Power Automate / Logic Apps: the callback URL of the trigger). An address this key already subscribed, or that an endpoint of a revoked or expired key holds: that endpoint is replaced (new id and secret). Held by another endpoint of the organization: 422 webhook.duplicateUrl."},"events":{"type":"array","items":{"type":"string","enum":["requirement.status_changed","submission.created","submission.reviewed","requirement.created","requirement.contested","requirement.message_received","relationship.status_changed","party.merged","party.compliance_changed","finding.created","finding.status_changed","organization.restored"]},"minItems":1,"uniqueItems":true},"description":{"type":["string","null"],"maxLength":120}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreated"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/webhooks/{id}":{"get":{"tags":["webhooks"],"operationId":"GetWebhook","summary":"Get a webhook endpoint of this key","security":[{"bearer":["write:webhooks"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["webhooks"],"operationId":"UpdateWebhook","summary":"Pause or resume an endpoint of this key","description":"active false pauses the endpoint, true resumes it with the same secret (one disabled after repeated failures too). Audited as webhook.disabled / webhook.enabled under the key's name.","security":[{"bearer":["write:webhooks"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["active"],"properties":{"active":{"type":"boolean","description":"false pauses the endpoint: nothing is sent to it; the events of the pause are never sent later, and deliveries still waiting for a retry are marked failed (catch up with updatedSince). true resumes it, the secret unchanged — an endpoint disabled after repeated failures too, once the receiver is fixed. The same value again records nothing."}},"additionalProperties":false}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["webhooks"],"operationId":"DeleteWebhook","summary":"Unsubscribe an endpoint","description":"The endpoint and its pending deliveries are deleted.","security":[{"bearer":["write:webhooks"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Deleted."},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/webhooks/{id}/rotate-secret":{"post":{"tags":["webhooks"],"operationId":"RotateWebhookSecret","summary":"Renew the signing secret of an endpoint","description":"A new signing secret for an endpoint of this key, in the answer this once. By default the current secret still signs for 24 hours next to the new one (webhook-signature lists both, the new one first): update the receiver within that time. keepPreviousSecret: false stops the current secret at once. A second renewal within the 24 hours drops the oldest secret. The body may be empty.","security":[{"bearer":["write:webhooks"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"keepPreviousSecret":{"type":"boolean","default":true,"description":"true (default): the current secret still signs for 24 hours next to the new one, the time to update the receiver. false: it stops at once (it leaked)."}},"additionalProperties":false}}}},"responses":{"200":{"description":"The endpoint with its new secret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreated"}}}},"400":{"description":"The body is not a JSON object (`api.invalidBody`), or it contains a field this endpoint does not document (`api.unknownField`, the fields are named in `message`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`) or action refused (`auth.forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Body larger than 65536 bytes (`api.payloadTooLarge`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Refused by the business rules: `validation.invalid` with `fieldErrors` (field -> error codes), or a specific code (`ref.duplicateCode`, `ref.duplicateName`, `ref.duplicateReference`, `ref.duplicateExternalRef`, `ref.duplicateRegistration`, `ref.duplicateContactEmail`, `fnd.duplicateOpen`, `fnd.tooManyOpen`, `fnd.notOpen`, `fnd.invalidTransition`, `ref.timezoneRequired`, `ref.parentArchived`, `ref.archived`, `ref.partyArchived`, `ref.unitSiteMismatch`, `ref.partyStillRelated`, `obl.duplicate`, `obl.typeNotPublished`, `obl.closed`, `org.suspended`, `org.closed`…). The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/exports":{"get":{"tags":["exports"],"operationId":"ListExports","summary":"List the full exports","description":"The 20 latest full exports of the organization, the latest first, whoever requested them (a member on the screen, a key).","security":[{"bearer":["read:export"]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Export"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["exports"],"operationId":"RequestExport","summary":"Request a full export","description":"Everything of the organization in one ZIP, as Settings > Data gives it: data.xlsx (one readable sheet per table), data/<table>.jsonl (every table, no limit), the documents (files/<type>/<subject>/<file>), sha256.txt and manifest.json (formats, counts, fingerprints, what is not shipped and why). Built in the background (the builder runs every 5 minutes): poll the Location (Retry-After), then download downloadUrl. An export requested by a key is kept 48 hours and sends no e-mail. 12 hours at least between two exports requested by the keys of the organization: a daily backup always passes.","security":[{"bearer":["read:export"]}],"responses":{"200":{"description":"An export is already under way (requested on the screen or by a key): this one, never a second build.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Export"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}}}},"202":{"description":"Requested: status pending.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Export"}}},"headers":{"Location":{"description":"Absolute URL of the created element (its GET).","schema":{"type":"string","format":"uri"}},"Retry-After":{"description":"Seconds before asking again (GET the Location).","schema":{"type":"integer"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`). Invalid Idempotency-Key (`api.invalidIdempotencyKey`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A request with the same Idempotency-Key is still running (`api.idempotencyKeyInProgress`, see `Retry-After`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"The Idempotency-Key was used for another request in the last 24 hours (`api.idempotencyKeyReused`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`api.exportTooSoon`: a key of the organization requested an export less than 12 hours ago (Retry-After: seconds until the next one), or the rate limit (`api.rateLimited`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":255},"description":"A unique value per write (a UUID), sent again unchanged when the request is retried after a lost answer. Within 24 hours, the same key and the same request (method, path, query, body) answer the first success again, with Idempotent-Replayed: true, without running it twice. Bound to the API key. Another request with the same key: 422 api.idempotencyKeyReused; the first one still running: 409 api.idempotencyKeyInProgress (Retry-After). An error answer is not kept: the corrected request may reuse the key — except a PATCH refused after one of its fields applied (fields apply in a documented order): that refusal is kept and answered again, the corrected request takes a new key."}]}},"/api/v1/exports/{id}":{"get":{"tags":["exports"],"operationId":"GetExport","summary":"Get a full export","description":"Its status; downloadUrl once done. While pending or running, Retry-After says when to ask again.","security":[{"bearer":["read:export"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Export"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/exports/{id}/file":{"get":{"tags":["exports"],"operationId":"GetExportFile","summary":"Download a full export","description":"The ZIP (Content-Length, ETag and Repr-Digest with its SHA-256). Resumable: Range: bytes=<from>- (or <from>-<to>, or -<last n>) answers 206 with Content-Range; with If-Range: <ETag>, a different version answers the whole file. Every request is recorded in the audit journal (organization.data_exported).","security":[{"bearer":["read:export"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"Range","in":"header","schema":{"type":"string"},"description":"One byte range, to resume a download: bytes=1048576-"},{"name":"If-Range","in":"header","schema":{"type":"string"},"description":"The ETag received: the range is served only if the file is still this one."}],"responses":{"200":{"description":"The ZIP.","content":{"application/zip":{"schema":{"type":"string","format":"binary"}}}},"206":{"description":"The bytes of the range asked for (Content-Range).","content":{"application/zip":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown id, or id of another organization (`api.notFound`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"`api.exportNotReady`: still pending or running (Retry-After), or failed (see its error).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"`api.exportExpired`: deleted after its availability; request a new one.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"416":{"description":"`api.rangeNotSatisfiable`: the range starts beyond the end of the file (Content-Range: bytes */<size>).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"`api.tooManyDownloads`: downloads of exports already under way for the organization (4 at once per server of the service; Retry-After), or the rate limit (`api.rateLimited`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The file storage cannot be reached right now (`file.storeUnavailable`): try again after the seconds of Retry-After.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/audit-events":{"get":{"tags":["audit"],"operationId":"ListAuditEvents","summary":"List audit events","description":"The audit journal for a SIEM, in the order the changes were committed (nearly chronological). Scope read:audit. Poll with after = the id of the last event received: an event is listed once every change started before it is committed, so the cursor never skips one (a long change anywhere delays the feed by its duration).","security":[{"bearer":["read:audit"]}],"parameters":[{"name":"after","in":"query","schema":{"type":"string","format":"uuid"},"description":"The id of the last event you received: the next events. An id that no longer exists: 400."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"since","in":"query","schema":{"type":"string","format":"date-time","description":"Events at or after this instant (first call)."}},{"name":"category","in":"query","schema":{"type":"string","enum":["security","reference","compliance","review","reminder","administration"]}},{"name":"action","in":"query","schema":{"type":"string","maxLength":80,"description":"One action, exactly (requirement.status_changed)."}},{"name":"entityType","in":"query","schema":{"type":"string","maxLength":40}},{"name":"entityId","in":"query","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data","nextCursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditEvent"}},"nextCursor":{"type":["string","null"],"description":"Pass as `after` to read the next page; null on the last page."}}}}}},"400":{"description":"Invalid or repeated parameter (`api.invalidParameter`), or a parameter this operation does not document (`api.unknownParameter`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, revoked or expired key (`api.unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Missing scope (`api.insufficientScope`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (`api.rateLimited`); see `Retry-After`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"API key `vgl_…`. Scopes: read:sites, read:parties, read:requirements, read:submissions, read:reminders, write:sites, write:parties, write:requirements, write:submissions, write:reminders, write:portal-links, write:import, read:export, read:calendar, read:audit, write:webhooks, read:settings, write:settings, read:members, write:members, write:reviews."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable: match on it."},"message":{"type":"string","description":"English sentence for a developer; may be reworded."},"requestId":{"type":"string","description":"Also in the X-Request-Id header of every answer, and on the audit events of a write: quote it to the support."},"docUrl":{"type":"string","format":"uri","description":"The list of error codes in the guide."},"fieldErrors":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}},"description":"Write endpoints, 422: error codes by field path (e.g. `name`: [`validation.tooShort`])."},"fields":{"type":"array","description":"fieldErrors with a sentence each; allowed: the accepted values of a list field.","items":{"type":"object","required":["field","code","message"],"properties":{"field":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"},"allowed":{"type":"array","items":{"type":"string"}}}}},"existingId":{"type":"string","format":"uuid","description":"A duplicate (site or portfolio code, portfolio name, unit or asset reference, third-party externalRef or registration number, requirement already followed, webhook address): the id of the element that already holds it."},"lastRemindedAt":{"type":"string","format":"date-time","description":"409 rmd.alreadyRemindedToday: when the last reminder of the requirement left."},"ip":{"type":["string","null"],"description":"403 api.ipNotAllowed: the address the call came from, as Vigilo saw it (add it to the key's allowed addresses); null when none was seen."}}}}},"Me":{"type":"object","properties":{"organization":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"key":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"prefix":{"type":"string"},"expiresAt":{"type":["string","null"],"format":"date-time"},"scopes":{"type":"array","items":{"type":"string","enum":["read:sites","read:parties","read:requirements","read:submissions","read:reminders","write:sites","write:parties","write:requirements","write:submissions","write:reminders","write:portal-links","write:import","read:export","read:calendar","read:audit","write:webhooks","read:settings","write:settings","read:members","write:members","write:reviews"]}},"allowedIps":{"type":"array","items":{"type":"string"},"description":"Addresses or ranges the key may call from (changed in Settings › API keys); empty: any address. A call from another address is refused (403 api.ipNotAllowed)."}}}}},"Site":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"portfolioId":{"type":["string","null"],"format":"uuid","description":"null: the site is in no portfolio."},"name":{"type":"string"},"code":{"type":["string","null"]},"siteType":{"type":"string"},"addressLine1":{"type":["string","null"]},"addressLine2":{"type":["string","null"]},"postalCode":{"type":["string","null"]},"city":{"type":["string","null"]},"region":{"type":["string","null"]},"regionCode":{"type":["string","null"],"readOnly":true,"description":"ISO 3166-2 code read from `region` and `country` (e.g. CA-ON), used by the assignment rules; null when the country has no subdivision list or the region is not recognized. Send `region` to change it."},"country":{"type":["string","null"],"description":"ISO 3166-1 alpha-2."},"timezone":{"type":["string","null"],"description":"IANA time zone; null: the organization's time zone applies."},"tags":{"type":"array","items":{"type":"string"}},"customFields":{"type":"object","additionalProperties":true,"description":"Custom fields defined in the organization settings, by identifier. Number and money fields: send JSON numbers (5000000, 12.5)."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"archivedAt":{"type":["string","null"],"format":"date-time"},"latitude":{"type":["number","null"]},"longitude":{"type":["number","null"]},"managerUserId":{"type":["string","null"],"format":"uuid","description":"Site manager: default owner of the site's new requirements; null: none."}}},"Portfolio":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"code":{"type":["string","null"]},"description":{"type":["string","null"]},"managerUserId":{"type":["string","null"],"format":"uuid","description":"Portfolio manager: default owner of the new requirements of its sites that have no site manager; null: none."},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"archivedAt":{"type":["string","null"],"format":"date-time"}}},"Unit":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"siteId":{"type":"string","format":"uuid"},"reference":{"type":"string","description":"Unique in its site, case ignored (B12 = b12)."},"name":{"type":["string","null"]},"unitType":{"type":"string","enum":["apartment","house","shop","office","storage","parking","warehouse","other"]},"floor":{"type":["string","null"]},"areaM2":{"type":["number","null"],"description":"Floor area in square metres."},"occupancyStatus":{"type":"string","enum":["occupied","vacant","unknown"],"description":"Follows the leases of the unit: occupied while one runs, vacant when the last one ends."},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"archivedAt":{"type":["string","null"],"format":"date-time"}}},"Asset":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"siteId":{"type":"string","format":"uuid"},"unitId":{"type":["string","null"],"format":"uuid","description":"The unit the equipment is in; null: the common parts of the site."},"assetKind":{"type":"string","description":"One of fire_extinguisher, fire_hose_reel, fire_alarm, sprinkler, smoke_extraction, emergency_lighting, fire_door, dry_riser, defibrillator, lift, escalator, automatic_door, electrical_installation, lightning_protection, gas_installation, boiler, chimney, ventilation, hvac, cooling_tower, water_system, pool, playground, sports_equipment, pressure_equipment, lifting_equipment, work_equipment, forklift, racking, dock_equipment, portable_appliance, vehicle, generator, solar_installation, tank, other or a kind added in the organization settings. The assignment rules read it (a lift gets its periodic inspections)."},"name":{"type":"string"},"reference":{"type":["string","null"],"description":"Your identifier of the equipment (the one of your maintenance tool)."},"serialNumber":{"type":["string","null"]},"manufacturer":{"type":["string","null"]},"model":{"type":["string","null"]},"installedOn":{"type":["string","null"],"format":"date"},"locationDetail":{"type":["string","null"]},"quantity":{"type":"integer","description":"Identical items followed as one line (12 extinguishers of a floor)."},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"archivedAt":{"type":["string","null"],"format":"date-time"}}},"Party":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string"},"displayName":{"type":"string"},"legalName":{"type":["string","null"]},"roles":{"type":"array","items":{"type":"string"}},"registrationNumber":{"type":["string","null"]},"vatNumber":{"type":["string","null"]},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"addressLine1":{"type":["string","null"]},"addressLine2":{"type":["string","null"]},"postalCode":{"type":["string","null"]},"city":{"type":["string","null"]},"region":{"type":["string","null"]},"regionCode":{"type":["string","null"],"readOnly":true,"description":"ISO 3166-2 code read from `region` and `country` (e.g. CA-ON), used by the assignment rules; null when the country has no subdivision list or the region is not recognized. Send `region` to change it."},"country":{"type":["string","null"]},"locale":{"type":["string","null"]},"externalRef":{"type":["string","null"]},"status":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"customFields":{"type":"object","additionalProperties":true,"description":"Custom fields defined in the organization settings, by identifier. Number and money fields: send JSON numbers (5000000, 12.5)."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"archivedAt":{"type":["string","null"],"format":"date-time"},"erasedAt":{"type":["string","null"],"format":"date-time","readOnly":true,"description":"Erased under the GDPR by an owner on the screen (at the person's request, or at the end of the retention period; a duplicate merged into it goes with it): name, numbers, addresses, contacts, its own documents and its texts are gone for good; the row stays archived under a neutral name for the history of its requirements, and the reports it deposited as a provider on other checks stay without its texts. Erase it as well in the systems that copied it (GDPR art. 17; art. 19 for those it was passed on to): follow updatedSince with includeArchived=true, or the party.erased events of GET /audit-events. Null: not erased."},"employerPartyId":{"type":["string","null"],"format":"uuid","description":"An individual's employer (a company among the third parties); null for a company or an individual without one."},"managerUserId":{"type":["string","null"],"format":"uuid","description":"Third-party manager (a member, see GET /members): default owner of its new requirements, told of its submissions and messages; null: none."},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"timezone":{"type":["string","null"],"description":"IANA time zone; null: the site's or the organization's applies."},"registry":{"type":"array","readOnly":true,"description":"The last answer of each official register asked about the party's current identifiers — Sirene (DINUM) for a French SIREN / SIRET, VIES (European Commission) for an EU VAT number — by a member's « Check in the register » or by the organization's periodic check (Settings › Third parties, every 6 months by default). Empty until a check; an answer about a former number is dropped. The party's updatedAt moves when an answer changes (status, closing date or published name), so an incremental sync (updatedSince) sees a company found closed; the same answer dated again leaves it as it is. Read it with compliance before paying a supplier: a company ceased at Sirene is closed whatever its documents.","items":{"type":"object","required":["source","identifier","status","name","closedOn","checkedAt"],"properties":{"source":{"type":"string","enum":["sirene","vies"],"description":"sirene: the French companies register; vies: EU VAT numbers."},"identifier":{"type":"string","description":"The number asked, normalized (upper case, no punctuation)."},"status":{"type":"string","enum":["active","ceased","establishment_closed","valid","invalid","not_found"],"description":"Sirene: active, ceased (company closed), establishment_closed (the SIRET closed while the company is active: update the number), not_found (unknown or not public). VIES: valid, invalid (not confirmed for intra-EU trade, not necessarily wrong)."},"name":{"type":["string","null"],"description":"The name the register publishes; null when it gives none."},"closedOn":{"type":["string","null"],"format":"date","description":"Sirene: closing date of the company or of the establishment."},"checkedAt":{"type":"string","format":"date-time","description":"When the register answered."}}}},"compliance":{"type":"object","readOnly":true,"description":"Whether the third party is in good standing, as the dashboard counts it: its inbound requirements (the third party is the subject), archived ones left out, waived ones counted as compliant unless the organization says otherwise. Read it before paying a supplier; the event party.compliance_changed tells each change. Updated within a minute of the change of a requirement.","properties":{"status":{"type":"string","enum":["non_compliant","pending","compliant","none"],"description":"non_compliant: at least one requirement overdue, expired or blocked. pending: none of those, at least one awaiting its document or its review. compliant: every requirement in good standing. none: no requirement applies."},"since":{"type":["string","null"],"format":"date-time","description":"When the status last changed; null: never changed since Vigilo started recording it."},"applicable":{"type":"integer","description":"Requirements counted (closed ones left out, and waived ones when they do not count)."},"compliant":{"type":"integer"},"nonCompliant":{"type":"integer"},"pending":{"type":"integer"}}},"identityProposal":{"type":["object","null"],"readOnly":true,"description":"A company's contact proposed from its portal to correct the third party's identity (« Your company » › « Suggest a correction »); nothing changes on the party until a member applies it on its page or a key with POST /parties/{id}/decide-identity. A new proposal replaces it (new id). Its arrival does not move the party's updatedAt: list them with GET /parties?identityProposal=true. null: none pending.","properties":{"id":{"type":"string","format":"uuid","description":"Send it back as proposalId to decide."},"proposedAt":{"type":"string","format":"date-time"},"contactId":{"type":"string","format":"uuid","description":"The contact who proposed it (GET /contacts/{id})."},"proposed":{"type":"object","description":"The proposed value of each field that still differs from the party, among legalName, registrationNumber, vatNumber, phone, addressLine1, addressLine2, postalCode, city, region, country; null: the field is cleared. Identifiers are normalized and the phone in E.164, as the party form stores them.","additionalProperties":{"type":["string","null"]}}},"required":["id","proposedAt","contactId","proposed"]}}},"Requirement":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"complianceTypeId":{"type":"string","format":"uuid"},"typeCode":{"type":"string"},"typeName":{"type":"object","additionalProperties":{"type":"string"},"description":"Text by language code (en, fr…): the languages the organization filled in."},"categoryKey":{"type":"string"},"subjectType":{"type":"string"},"subjectId":{"type":"string","format":"uuid"},"partyId":{"type":["string","null"],"format":"uuid","description":"The third party that provides the evidence: the subject itself for a third-party subject, or the provider in charge of a site / unit / asset / organization requirement (null: none)."},"siteId":{"type":["string","null"],"format":"uuid"},"unitId":{"type":["string","null"],"format":"uuid"},"assetId":{"type":["string","null"],"format":"uuid"},"portfolioId":{"type":["string","null"],"format":"uuid"},"status":{"type":"string","enum":["not_requested","requested","submitted","in_review","rejected","compliant","expiring_soon","overdue","expired","waived","closed"]},"dueDate":{"type":["string","null"],"format":"date"},"validFrom":{"type":["string","null"],"format":"date"},"validUntil":{"type":["string","null"],"format":"date"},"priority":{"type":"string"},"ownerUserId":{"type":["string","null"],"format":"uuid","description":"The member in charge; null when nobody is."},"waivedUntil":{"type":["string","null"],"format":"date"},"isBlocked":{"type":"boolean"},"openFindingsCount":{"type":"integer"},"currentSubmissionId":{"type":["string","null"],"format":"uuid"},"lastApprovedSubmissionId":{"type":["string","null"],"format":"uuid"},"source":{"type":"string"},"direction":{"type":"string","enum":["inbound","outbound"],"description":"inbound (collected) or outbound (produced and sent by the organization)."},"customFields":{"type":"object","additionalProperties":true,"description":"Custom fields defined in the organization settings, by identifier. Number and money fields: send JSON numbers (5000000, 12.5)."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"archivedAt":{"type":["string","null"],"format":"date-time"},"relationshipId":{"type":["string","null"],"format":"uuid","description":"The relationship (lease, contract…) this requirement belongs to: closed when it ends. null: tied to none."},"complianceTypeVersionId":{"type":"string","format":"uuid","description":"The version of the type it follows (fields, recurrence)."},"assignmentRuleId":{"type":["string","null"],"format":"uuid","description":"The assignment rule that created it; null: created by hand or by an import."},"outOfRuleSince":{"type":["string","null"],"format":"date-time","description":"Set when the rule that created it no longer selects its subject."},"timezone":{"type":"string","description":"IANA time zone its dates are computed in (the site's, else the organization's)."},"currentSubmissionStatus":{"type":["string","null"],"enum":["pending_review","in_review","approved","rejected",null],"description":"Status of the latest document sent; null: none."},"waivedReason":{"type":["string","null"]},"waiverRequest":{"type":["object","null"],"readOnly":true,"description":"A waiver asked for and awaiting the approval of another owner or admin (Settings › Statuses and steps › « A waiver takes effect once another administrator approves it »); status and reminders are unchanged meanwhile. Approved or refused in the application, or with POST /requirements/{id}/decide-waiver (send requestedAt back). null: none pending.","properties":{"reason":{"type":"string"},"until":{"type":["string","null"],"format":"date","description":"End of the waiver asked for; null: no end."},"requestedAt":{"type":"string","format":"date-time"}},"required":["reason","until","requestedAt"]},"closedAt":{"type":["string","null"],"format":"date-time"},"closedReason":{"type":["string","null"],"enum":["subject_archived","relationship_ended","type_deactivated","manual",null],"description":"Why it was closed (status closed); null while open."},"closedNote":{"type":["string","null"],"description":"The reason given when it was excluded (closedReason manual; when an import was undone, the note naming it), or the note of another closure; null while open."},"checkpointDoneAt":{"type":["string","null"],"format":"date-time","description":"When the organization's own reminder step (Settings › Statuses and steps) was ticked; null: not ticked, or no such step."},"notConcerned":{"type":["object","null"],"readOnly":true,"description":"The third party said « This does not concern me » on its portal, with its reason: the automatic reminders are paused (reminders.pausedUntil, one year) until a member decides — exclude it (excluded: true), waive it, entrust it to another provider (partyId), change the pause, or a document is sent. Its updatedAt moves with the report. null: no report awaiting a decision (also once closed or waived).","properties":{"reason":{"type":"string"},"reportedAt":{"type":"string","format":"date-time"}},"required":["reason","reportedAt"]},"keptRequirementId":{"type":["string","null"],"format":"uuid","readOnly":true,"description":"Closed and archived by the merge of two duplicate third parties: the requirement kept in its place, to follow from now on. null for every other requirement."},"handling":{"type":"string","enum":["platform","client"],"readOnly":true,"description":"Who follows it up, as it applies now: platform (the Vigilo team calls and reviews, managed service) or client (the organization's team). Always client for a self-service organization."},"handlingSetting":{"type":"string","enum":["inherit","platform","client"],"description":"Its own choice: inherit follows its compliance type's handling. Written with PATCH by a key that also has write:settings."},"bucket":{"type":"string","enum":["compliant","non_compliant","pending","excluded"],"description":"Dashboard group: non_compliant (overdue, expired or blocked by an open finding), compliant (compliant, expiring soon), excluded (closed), pending (the others); waived is compliant or excluded depending on the organization setting. Counting the rows of a bucket gives the dashboard's figure."},"reminders":{"type":"object","properties":{"count":{"type":"integer","description":"Reminders sent for the current request, to the current recipient: back to 0 (with lastSentAt null) when the requirement is entrusted to another provider or a document is approved (a new cycle: the renewal opens with the request); the emails sent before stay listed by GET /api/v1/reminders."},"lastSentAt":{"type":["string","null"],"format":"date-time"},"nextAt":{"type":["string","null"],"format":"date-time","description":"Next automatic reminder; null: none planned."},"pausedUntil":{"type":["string","null"],"format":"date-time"},"block":{"type":["string","null"],"enum":["no_recipient","exhausted","party_unrelated",null],"description":"Why reminders cannot go out (no recipient, all steps sent, party no longer related); null: none."}}}}},"Relationship":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"partyId":{"type":"string","format":"uuid"},"siteId":{"type":["string","null"],"format":"uuid"},"unitId":{"type":["string","null"],"format":"uuid","description":"A unit of the site (lease of a unit); null: the whole site."},"relationType":{"type":"string","enum":["lease","contract","assignment","maintenance","employment","other"]},"reference":{"type":["string","null"]},"startsOn":{"type":"string","format":"date"},"endsOn":{"type":["string","null"],"format":"date"},"status":{"type":"string","enum":["upcoming","active","ended"],"description":"From the dates, in the site's time zone: upcoming before startsOn, ended after endsOn, active between."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"archivedAt":{"type":["string","null"],"format":"date-time"}}},"Contact":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"partyId":{"type":"string","format":"uuid"},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"email":{"type":["string","null"]},"phone":{"type":["string","null"],"description":"E.164 (+33612345678)."},"jobTitle":{"type":["string","null"]},"locale":{"type":["string","null"],"enum":["en","fr","de","es","it","pt","nl","pl","sv","da","nb","fi","cs","ro","hu","el","tr","ja","zh","ar",null],"description":"Language of the emails and of the portal for this contact; null: its third party's language, followed when it changes."},"isPrimary":{"type":"boolean","description":"One primary contact per third party."},"receivesRequests":{"type":"boolean","description":"The requests and reminders are sent to this contact."},"fromPartyEmail":{"type":"boolean","readOnly":true,"description":"Made from the third party's own email: it receives the requests only while no other contact does, and becomes a contact like any other once updated."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"archivedAt":{"type":["string","null"],"format":"date-time"},"portalEmailChange":{"type":["object","null"],"readOnly":true,"description":"The contact changed its own address on its portal (applied once it typed the code sent to the new address; its updatedAt moves) and the change can still be undone: POST /contacts/{id}/revert-email-change puts previousEmail back until revertibleUntil. null: no such change, older than 30 days, already undone, or the address changed since.","properties":{"id":{"type":"string","format":"uuid","description":"Send it back as changeId to undo it."},"previousEmail":{"type":["string","null"],"description":"The address it replaced."},"changedAt":{"type":"string","format":"date-time"},"revertibleUntil":{"type":"string","format":"date-time"}},"required":["id","previousEmail","changedAt","revertibleUntil"]}}},"Finding":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"requirementId":{"type":"string","format":"uuid"},"title":{"type":"string"},"description":{"type":["string","null"]},"severity":{"type":"string","enum":["critical","major","minor","observation"]},"status":{"type":"string","enum":["open","in_progress","resolved","verified","wont_fix"],"description":"open and in_progress count as open on the requirement (openFindingsCount); resolved waits for a member's verification; verified and wont_fix close it, until a member reopens it with a reason (back to open; POST /findings/{id}/decide with action reopen)."},"dueDate":{"type":["string","null"],"format":"date","description":"Correct before this day."},"overdue":{"type":"boolean","description":"Still open and past dueDate, on the requirement's calendar (its timezone)."},"assigneeUserId":{"type":["string","null"],"format":"uuid","description":"The member who corrects it; null: nobody."},"resolutionNote":{"type":["string","null"],"description":"What was done (resolved), or why it will not be corrected (wont_fix)."},"sharedWithParty":{"type":"boolean","description":"Listed on the third party's portal and announced to it by email; the third party may answer how it was resolved (resolvedByContactId)."},"submissionId":{"type":["string","null"],"format":"uuid","description":"The submission whose report listed it, raised when the report was approved; null for a finding raised by hand or through the API."},"resolvedByContactId":{"type":["string","null"],"format":"uuid","description":"The contact of the third party who marked it resolved from the portal (GET /api/v1/contacts/{id}); resolvedBy is null then."},"reopenNote":{"type":["string","null"],"description":"Why a member sent the third party's answer back, or reopened the finding it had answered (shown on its portal while the finding is open again)."},"createdBy":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["member","former_member","support","api_key"],"description":"support: Vigilo staff acting on your request (no identity); api_key: through the API, by that key."},"id":{"type":["string","null"],"format":"uuid","description":"User or API key id; null for support."}},"description":"Who raised it; null when the API key that raised it no longer exists."},"resolvedBy":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["member","former_member","support","api_key"],"description":"support: Vigilo staff acting on your request (no identity); api_key: through the API, by that key."},"id":{"type":["string","null"],"format":"uuid","description":"User or API key id; null for support."}},"description":"Who resolved or discarded it; null while it is open, and when the third party resolved it from the portal (resolvedByContactId)."},"resolvedAt":{"type":["string","null"],"format":"date-time"},"verifiedBy":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["member","former_member","support","api_key"],"description":"support: Vigilo staff acting on your request (no identity); api_key: through the API, by that key."},"id":{"type":["string","null"],"format":"uuid","description":"User or API key id; null for support."}},"description":"The member who verified the correction (never the one who resolved it)."},"verifiedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Reminder":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"requirementIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The requirements the email asks for (one email can group several requirements of the party)."},"partyId":{"type":"string","format":"uuid","description":"The third party written to."},"contactId":{"type":["string","null"],"format":"uuid","description":"The contact written to; null: the third party's own email, or the owner of an outbound requirement reminded internally (toAddress is then a member's email)."},"channel":{"type":"string","enum":["email"]},"templateKey":{"type":"string","description":"Kind of email: request_initial, reminder_before_due, reminder_overdue, final_notice, receipts…"},"locale":{"type":"string","description":"Language of the email."},"trigger":{"type":"string","enum":["reminder_step","manual","system"],"description":"reminder_step: planned by the reminder settings; manual: « remind now » (screen or API); system: a receipt or a notice."},"status":{"type":"string","enum":["queued","sent","failed"],"description":"queued while it is handed to the mail server; sent; failed: refused by the mail server (check the address of the contact)."},"toAddress":{"type":"string"},"cc":{"type":"array","items":{"type":"string"}},"subject":{"type":"string"},"contentSha256":{"type":"string","description":"SHA-256 of the subject, text and HTML really sent (proof of content)."},"queuedAt":{"type":"string","format":"date-time"},"sentAt":{"type":["string","null"],"format":"date-time"},"sentBy":{"type":"object","properties":{"type":{"type":"string","enum":["member","former_member","support","api_key","system"]},"id":{"type":["string","null"],"format":"uuid"}},"description":"Who asked for it: a member or an API key (« remind now »), else system (planned steps, receipts)."},"bodyText":{"type":"string","description":"GET /api/v1/reminders/{id} only: the text sent, the portal link masked."}}},"Message":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"requirementId":{"type":"string","format":"uuid"},"partyId":{"type":["string","null"],"format":"uuid","description":"The third party the requirement is followed with now."},"from":{"type":"string","enum":["party","organization"],"description":"party: written by a contact on its portal; organization: by a member or an API key."},"author":{"type":"object","properties":{"type":{"type":"string","enum":["contact","member","former_member","support","api_key"]},"id":{"type":["string","null"],"format":"uuid","description":"The contact (GET /api/v1/contacts/{id}), the member or the API key; null when the key that wrote it no longer exists."}}},"body":{"type":"string","maxLength":2000,"description":"The text, as written (never edited). *** once erased at the third party's request (GDPR)."},"createdAt":{"type":"string","format":"date-time"}}},"PortalLink":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"partyId":{"type":"string","format":"uuid"},"contactId":{"type":["string","null"],"format":"uuid","description":"The contact the link opens the portal to (GET /api/v1/contacts/{id}); a code for a sensitive requirement goes to its email. Null for a forwarded link: see delegate."},"delegatedFromId":{"type":["string","null"],"format":"uuid","description":"A link a contact forwarded from its own (to its insurer, accountant, a colleague: one requirement, 30 days): the link it was forwarded from; it stops with it. Null for the organization's links."},"delegate":{"type":["object","null"],"properties":{"name":{"type":"string"},"email":{"type":["string","null"],"format":"email"}},"description":"A forwarded link: the name and address the contact typed (that person is not a contact of the third party)."},"scope":{"type":"string","enum":["all_open","requirement_ids"],"description":"all_open: every open requirement of the third party, read at each opening; requirement_ids: only those listed."},"requirementIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"The requirements of a requirement_ids link (empty for all_open)."},"active":{"type":"boolean","description":"The link opens the portal now: not revoked, not expired, third party and contact not archived; a forwarded link, while the link it was forwarded from is active too."},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time","description":"30 days after its creation (a forwarded link also stops with the link it was forwarded from)."},"lastUsedAt":{"type":["string","null"],"format":"date-time","description":"Last opening by the third party; null: never opened."},"useCount":{"type":"integer","description":"Pages and actions of the portal through this link."},"revokedAt":{"type":["string","null"],"format":"date-time"},"revokedReason":{"type":["string","null"],"enum":["regenerated","manual","contact_email_changed","party_archived","otp_locked","key_revoked"],"description":"regenerated: replaced by a new link; manual: revoked by a member or a key, or its contact archived, or a forward cancelled by the contact who made it; contact_email_changed; party_archived; otp_locked: three codes locked by wrong attempts; key_revoked: the API key that issued it was revoked."},"createdBy":{"type":"object","properties":{"type":{"type":"string","enum":["member","former_member","support","api_key","system"]},"id":{"type":["string","null"],"format":"uuid"}},"description":"The member (« Copy link »), the API key, or system: a link of a request or reminder email (or one whose issuer no longer exists), or a link a contact forwarded (see delegatedFromId)."},"url":{"type":"string","format":"uri","description":"POST /api/v1/portal-links only: the address to send, given once (Vigilo keeps only its hash)."}}},"ComplianceType":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"code":{"type":"string","description":"Unique in the organization; accepted as complianceTypeCode by POST /requirements."},"name":{"type":"object","additionalProperties":{"type":"string"},"description":"Text by language code (en, fr…): the languages the organization filled in."},"description":{"type":["object","null"],"additionalProperties":{"type":"string"},"description":"Text by language code (en, fr…): the languages the organization filled in."},"categoryKey":{"type":"string"},"subjectType":{"type":"string","enum":["party","site","unit","asset","organization"]},"partyRoles":{"type":"array","items":{"type":"string"},"description":"Third-party types only: the roles it applies to (empty: any)."},"assetKinds":{"type":"array","items":{"type":"string"},"description":"Equipment types only: the kinds it applies to (empty: any)."},"country":{"type":["string","null"],"description":"ISO 3166-1 alpha-2 country of the obligation; null: any."},"region":{"type":["string","null"],"description":"ISO 3166-2 code when the obligation is regional."},"partyOrigin":{"type":["string","null"],"enum":["domestic","foreign",null],"description":"Third parties established in the country (domestic) or outside it (foreign); null: any."},"personalData":{"type":["string","null"],"enum":["employees","health",null],"description":"The document names workers (employees) or holds health data (health); null: none."},"legalBasis":{"type":["string","null"]},"sourceUrl":{"type":["string","null"]},"libraryCode":{"type":["string","null"],"description":"Code of the Vigilo library template it comes from; null: created by the organization."},"isActive":{"type":"boolean","description":"false: deactivated, no new requirement can use it."},"handling":{"type":"string","enum":["platform","client"],"description":"Who follows its requirements up: platform (the Vigilo team calls the parties who do not answer the reminders and reviews their documents, managed service) or client (the organization's own team). Always client for a self-service organization. Requirements may override it (handlingSetting). Written with PATCH (write:settings)."},"remindersEnabled":{"type":"boolean","description":"false: no automatic reminder for its requirements."},"reminderLevel":{"type":["string","null"],"enum":["gentle","standard","firm",null],"description":"How firm its reminder calendar is: gentle, standard or firm; null: the organization's calendar for its evidence kind."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"currentVersion":{"type":["object","null"],"description":"The published version new requirements follow; null: not published yet (POST /requirements answers 422 obl.typeNotPublished).","properties":{"id":{"type":"string","format":"uuid"},"version":{"type":"integer"},"evidenceKind":{"type":"string","enum":["document","inspection_report","form","declaration"]},"initialDueDays":{"type":"integer","description":"Default due date of a new requirement: today + this many days."},"recurrence":{"type":"object","properties":{"mode":{"type":"string","enum":["fixed_interval","on_expiry","one_time","event_based"]},"intervalMonths":{"type":["integer","null"]},"defaultValidityMonths":{"type":["integer","null"]}}},"expiringSoonDays":{"type":"integer","description":"A requirement is expiring_soon this many days before its validity ends."},"graceDays":{"type":"integer","description":"Days after the due date before a requirement turns overdue."},"reviewMode":{"type":"string","enum":["auto_approve","single","double"],"description":"auto_approve: approved on receipt when its files are clean and its values valid and current (else it waits for a review); single: one person approves; double: two different people approve in turn (four-eyes review)."},"checklist":{"type":"array","description":"Points the reviewer ticks before approving; a blocking one must be ticked. A document gives its answers (GET /submissions, checklist).","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"object","additionalProperties":{"type":"string"},"description":"Text by language code (en, fr…): the languages the organization filled in."},"blocking":{"type":"boolean"}}}},"findingsBlockCompliance":{"type":"string","enum":["none","critical","any_open"],"description":"Open findings that keep a requirement non-compliant: none, critical ones, or any open one."},"minFiles":{"type":"integer","description":"Files required with each document (0: none)."},"maxFileMb":{"type":"integer","description":"Largest file accepted, in MB (screens, portal and POST /files)."},"acceptedMimeTypes":{"type":"array","items":{"type":"string"},"description":"File types a submission accepts (screens, portal and POST /files): the type's own choice, narrowed by the platform's list. Another type is refused."},"provider":{"type":"string","enum":["subject","inspection_body","owner","client"],"description":"Who provides the document: subject (the third party itself, or the provider in charge), inspection_body, owner or client."},"otpRequired":{"type":"boolean","description":"A portal link to one of its requirements asks for a code sent by email first."},"documentPerRequirement":{"type":"boolean","description":"The document is specific to each request: never reused from another requirement on the portal."},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"Identifier of the value in a submission."},"type":{"type":"string","enum":["text","long_text","number","money","date","boolean","select","multi_select","email","phone","url"]},"label":{"type":"object","additionalProperties":{"type":"string"},"description":"Text by language code (en, fr…): the languages the organization filled in."},"required":{"type":"boolean"},"options":{"type":["array","null"],"items":{"type":"string"},"description":"Allowed values of a list field."},"optionLabels":{"type":["object","null"],"additionalProperties":{"type":"object","additionalProperties":{"type":"string"},"description":"Text by language code (en, fr…): the languages the organization filled in."},"description":"Label of each option by language, keyed by the stored value; null: the values are the labels."},"alertOptions":{"type":"array","items":{"type":"string"},"description":"Values of options flagged to the reviewer (a failed inspection, an entry in a register): the submission waits for a person, never approved automatically. Empty: none."},"min":{"type":["number","null"]},"max":{"type":["number","null"]},"integer":{"type":"boolean","description":"Number field: a count or a year, decimals refused."},"currency":{"type":["string","null"],"description":"ISO 4217 currency of a money field; null: chosen by the submitter."},"validityMonths":{"type":["integer","null"],"description":"Date field: the document stays valid at most this many months after it."},"personal":{"type":"boolean","description":"Text field identifying a person (a name, a personal certificate or licence number): never asked of an AI reading the document."},"help":{"type":["object","null"],"additionalProperties":{"type":"string"},"description":"Text by language code (en, fr…): the languages the organization filled in."}}},"description":"Values collected with each document."},"publishedAt":{"type":["string","null"],"format":"date-time"}}}}},"Settings":{"type":"object","properties":{"siteTypes":{"type":"array","maxItems":50,"items":{"type":"string","minLength":1,"maxLength":60},"description":"Site types the organization added to the delivered ones, shown as typed (no comma). Sent: replaces the whole list (send it back with the new value). Twice the same value, or a delivered one (its code or its name in any language of Vigilo, case and accents ignored): 422 set.listDuplicate; a value already saved before Vigilo delivered the same word stays accepted. A value removed while an active site or asset still carries it, or a rule or a compliance type names it: 422 set.siteTypeInUse / set.assetKindInUse / set.listValueInRule / set.listValueInType with the value and the count."},"assetKinds":{"type":"array","maxItems":50,"items":{"type":"string","minLength":1,"maxLength":60},"description":"Equipment kinds the organization added to the delivered ones, shown as typed (no comma). Sent: replaces the whole list (send it back with the new value). Twice the same value, or a delivered one (its code or its name in any language of Vigilo, case and accents ignored): 422 set.listDuplicate; a value already saved before Vigilo delivered the same word stays accepted. A value removed while an active site or asset still carries it, or a rule or a compliance type names it: 422 set.siteTypeInUse / set.assetKindInUse / set.listValueInRule / set.listValueInType with the value and the count."},"initialDueDays":{"type":"integer","minimum":0,"maximum":365,"description":"Days given to provide the first document, for a compliance type activated or created from now on (each type keeps its own afterwards). Default 30."},"expiringSoonDays":{"type":"integer","minimum":0,"maximum":180,"description":"Days before expiry a requirement turns « expiring soon », for a new type. Default 30."},"graceDays":{"type":"integer","minimum":0,"maximum":90,"description":"Days after the due date before a requirement turns overdue, for a new type. Default 0."},"partyIdentifiers":{"type":"object","additionalProperties":false,"description":"Settings › Third parties: rules applied when a third party is created or changed (screens, import, this API). Only a change is checked: a party recorded before keeps its other edits. Fields sent are changed, the others kept.","properties":{"registryRecheckMonths":{"type":"integer","enum":[0,1,3,6,12],"description":"Months between two periodic checks of the parties' identifiers at the official registers (Sirene, VIES): 0 never, 1, 3, 6 (default) or 12. The check runs nightly on active companies with a running relationship or an open requirement, 100 parties a day per organization; a company found closed or a VAT number no longer confirmed notifies the party's manager (else the owners and admins) and shows in each party's registry. Any other value is refused with 422."},"registrationRequired":{"type":"boolean","description":"A company needs its registrationNumber (individuals are exempt): a company created without one, or a number emptied, is refused with 422 ref.registrationNumberRequired. Default false."},"rejectInvalid":{"type":"boolean","description":"An invalid registrationNumber (checked in FR: SIREN, SIRET, RNA; GB: company number; any non-empty value elsewhere) or vatNumber (EU format, and the check digits of FR, AT, BE, DE, DK, EE, EL, ES, FI, HR, HU, IT, LU, MT, NL, PL, PT, RO, SE, SI, SK; elsewhere two letters and a number) is refused with 422 ref.registrationNumberInvalid / ref.vatNumberInvalid instead of a warning. Default false."}}},"deliveredSiteTypes":{"type":"array","items":{"type":"string"},"description":"The site types Vigilo delivers (codes): with siteTypes, what a site may carry (siteType)."},"deliveredAssetKinds":{"type":"array","items":{"type":"string"},"description":"The equipment kinds Vigilo delivers (codes): with assetKinds, what an asset may carry (assetKind)."}}},"CustomField":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"entity":{"type":"string","enum":["site","party","requirement"],"description":"What carries the field: sites, third parties or requirements (their customFields)."},"key":{"type":"string","description":"The key of the value in customFields; never changes."},"label":{"type":"object","additionalProperties":{"type":"string"},"description":"Text by language code (en, fr…): the languages the organization filled in."},"fieldType":{"type":"string","enum":["text","long_text","number","money","date","boolean","select","multi_select","email","phone","url"],"description":"Never changes through the API (converted on the screen, with a preview of the values)."},"options":{"type":["array","null"],"items":{"type":"string"},"description":"The values of a select or multi_select field; null otherwise."},"required":{"type":"boolean","description":"Asked when a form or a call sends the custom fields; existing records are not refused."},"position":{"type":"integer","description":"Display order among the fields of the entity."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"archivedAt":{"type":["string","null"],"format":"date-time","description":"Archived: no longer shown nor asked, the stored values are kept."}}},"Rule":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"complianceTypeId":{"type":"string","format":"uuid","description":"The compliance type the rule asks for (GET /compliance-types); never changes."},"subjectType":{"type":"string","enum":["party","site","unit","asset","organization"],"description":"The type's subject type."},"isActive":{"type":"boolean","description":"Active: creates the requirements of the subjects it covers, now and as they arrive."},"selector":{"type":"object","additionalProperties":false,"properties":{"partyRoles":{"type":"array","items":{"type":"string","enum":["tenant","supplier","subcontractor","contractor","service_provider","inspection_body","broker","employee","owner","other"]}},"relationTypes":{"type":"array","items":{"type":"string","enum":["lease","contract","assignment","maintenance","employment","other"]}},"portfolioIds":{"type":"array","items":{"type":"string","format":"uuid"}},"siteIds":{"type":"array","items":{"type":"string","format":"uuid"}},"siteTypes":{"type":"array","items":{"type":"string","maxLength":60},"description":"Delivered codes or values added in GET /settings; another value: 422 validation.optionInvalid."},"unitTypes":{"type":"array","items":{"type":"string","enum":["apartment","house","shop","office","storage","parking","warehouse","other"]}},"assetKinds":{"type":"array","items":{"type":"string","maxLength":60},"description":"Delivered codes or values added in GET /settings; another value: 422 validation.optionInvalid."},"tagsAny":{"type":"array","items":{"type":"string","maxLength":40},"description":"At least one of these tags."},"countries":{"type":"array","items":{"type":"string"},"description":"ISO 3166-1 alpha-2 countries or ISO 3166-2 regions (GB-SCT, US-CA…)."},"customFields":{"type":"array","maxItems":5,"description":"Conditions on a custom field (GET /settings/custom-fields): the third party's for a third-party rule, the site's for a site, unit or equipment rule. All must match. Usable types and operators: select and multi_select → any_of (values: some of the field's options); number and money → at_least / at_most (number, bound included; money in the organization's currency); boolean → is_true / is_false (false: unticked or never filled in). Another type, an archived or unknown key, an option not in the list: 422 naming the condition (selector.customFields.0.values…). In a PATCH, a selector without customFields keeps the stored conditions; [] removes them.","items":{"type":"object","additionalProperties":false,"required":["key","op"],"properties":{"key":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,62}$","description":"Key of the custom field."},"op":{"type":"string","enum":["any_of","at_least","at_most","is_true","is_false"]},"values":{"type":"array","maxItems":100,"items":{"type":"string","maxLength":100},"description":"any_of: options of the field (OR); ignored by the other operators (answered empty)."},"number":{"type":["number","null"],"description":"at_least / at_most: the bound; ignored by the other operators (answered null)."}}}},"perRelationship":{"type":["boolean","null"],"description":"Third-party rules: one requirement per lease or contract (true, the default) or one per third party (false); null: the default."}},"description":"The criteria: an empty list is not used (every value matches), perRelationship null is the default."},"duePolicy":{"type":"object","additionalProperties":false,"required":["from"],"properties":{"from":{"type":"string","enum":["creation","relationship_start","fixed_date"],"description":"creation: the day the requirement is created; relationship_start: the start of the lease or contract (third-party rules); fixed_date: fixedDate."},"offsetDays":{"type":["integer","null"],"minimum":-365,"maximum":365,"description":"Days added to the start; null with creation: the delay of the type's version."},"fixedDate":{"type":["string","null"],"format":"date"}}},"lastEvaluatedAt":{"type":["string","null"],"format":"date-time"},"lastEvaluation":{"type":["object","null"],"description":"What the last evaluation did: subjects matched, requirements created, already there, excluded on the screen, no longer covered (outOfRule), created with their reminders paused (held); skippedReason when nothing could be created.","properties":{"matched":{"type":"integer"},"created":{"type":"integer"},"existing":{"type":"integer"},"excluded":{"type":"integer"},"outOfRule":{"type":"integer"},"held":{"type":"integer"},"skippedReason":{"type":["string","null"],"enum":["type_inactive","type_not_published","rule_inactive",null]}}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"RulePreview":{"type":"object","required":["isActive","skippedReason","matched","toCreate","existing","excluded","carriedOver","setAside","outsideCountry","firstRequests","otherFormRules"],"properties":{"isActive":{"type":"boolean","description":"The rule after the save."},"skippedReason":{"type":["string","null"],"enum":["rule_inactive","type_inactive","type_not_published",null],"description":"Why the save itself would create nothing (toCreate is then what the rule creates once active, its type active and published); null: the save creates toCreate requirements."},"matched":{"type":"integer","minimum":0,"description":"Subjects the criteria cover."},"toCreate":{"type":"integer","minimum":0,"description":"Requirements the evaluation would create."},"existing":{"type":"integer","minimum":0,"description":"Covered subjects that already have an open requirement of the type (kept, never doubled)."},"excluded":{"type":"integer","minimum":0,"description":"Covered subjects whose requirement of the type was excluded by hand: never created again."},"carriedOver":{"type":"integer","minimum":0,"description":"Requirements to create that take over the third party's approved document of the other form (per contract / per third party)."},"setAside":{"type":"integer","minimum":0,"description":"Subjects matching the other criteria but left out by the type's own roles or equipment kinds, or by the country criterion."},"outsideCountry":{"type":["object","null"],"required":["country","count"],"description":"National or regional type: covered subjects located outside its place; null: none or a type of any country.","properties":{"country":{"type":"string","description":"The type's country, or its ISO 3166-2 region."},"count":{"type":"integer","minimum":0,"description":"Covered subjects outside it."}}},"firstRequests":{"type":["object","null"],"required":["soon","soonAt","later","laterFrom","noRecipient"],"description":"Third parties the created requirements will write to; null when nothing leaves (skippedReason, holdRequests true, automatic reminders off for the type or the organization, nothing to create).","properties":{"soon":{"type":"integer","minimum":0,"description":"Third parties written to at the next sending."},"soonAt":{"type":["string","null"],"format":"date-time","description":"The earliest of those sendings."},"later":{"type":"integer","minimum":0,"description":"Third parties written to later, when the first step of their calendar comes."},"laterFrom":{"type":["string","null"],"format":"date","description":"The local date of the first of those."},"noRecipient":{"type":"integer","minimum":0,"description":"Third parties without any contact to write to: nothing leaves until one is added."}}},"otherFormRules":{"type":"array","description":"The other active rules of the type asking it under the other form (per contract / per third party): a third party they share gets two requirements.","items":{"type":"object","required":["id","name","perRelationship"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"perRelationship":{"type":"boolean"}}}}}},"ComplianceTypePreview":{"type":"object","required":["isActive","openRequirements","closed","reopened","reopenable","activeRules"],"properties":{"isActive":{"type":"boolean","description":"The type after the call."},"openRequirements":{"type":"integer","minimum":0,"description":"Open requirements of the type now."},"closed":{"type":"integer","minimum":0,"description":"Requirements the call would close (isActive false with closeRequirements true)."},"reopened":{"type":"integer","minimum":0,"description":"Requirements the call would reopen (isActive true on a deactivated type)."},"reopenable":{"type":"integer","minimum":0,"description":"Requirements closed by a deactivation whose subject and lease are still followed: what a reactivation reopens."},"activeRules":{"type":"integer","minimum":0,"description":"Active rules of the type: without effect while it is deactivated, evaluated by a reactivation (POST /rules/{id}/preview tells what each would create)."}}},"Member":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid","description":"The person's account: what ownerUserId of a requirement names."},"name":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["owner","admin","manager","viewer"],"description":"owner and admin manage the organization; a manager works on the data of their scope; a viewer reads it."},"scopeAll":{"type":"boolean","description":"true: the whole organization. false: only the portfolios and sites listed (managers and viewers)."},"portfolioIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":200,"description":"Portfolios reached, with all their sites (scopeAll false)."},"siteIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500,"description":"Sites reached one by one (scopeAll false)."},"accessUntil":{"type":["string","null"],"format":"date","description":"Last day of a temporary access, in the organization's time zone (viewers only, an auditor for instance; at most 365 days ahead); null: no end."},"absence":{"type":["object","null"],"required":["from","until","deputyMemberId"],"properties":{"from":{"type":"string","format":"date","description":"First day of the absence, in the organization's time zone (today at the earliest when written, at most 366 days ahead)."},"until":{"type":"string","format":"date","description":"Last day, included (at most 186 days from the first)."},"deputyMemberId":{"type":["string","null"],"format":"uuid","description":"The member (id of GET /members) who also receives the absent member's notices and internal reminders meanwhile; null once that member left (nothing is copied any more)."}},"description":"Current or planned absence; null: none (an ended one reads null). Nothing moves: the member stays responsible of what they follow."},"lastSignInAt":{"type":["string","null"],"format":"date-time","description":"Last sign-in to Vigilo, whatever the organization; null: never signed in."},"joinedAt":{"type":"string","format":"date-time","description":"When they joined the organization."}}},"Invitation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["admin","manager","viewer"]},"scopeAll":{"type":"boolean","description":"true: the whole organization. false: only the portfolios and sites listed (managers and viewers)."},"portfolioIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":200,"description":"Portfolios reached, with all their sites (scopeAll false)."},"siteIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500,"description":"Sites reached one by one (scopeAll false)."},"accessUntil":{"type":["string","null"],"format":"date","description":"Last day of a temporary access, in the organization's time zone (viewers only, an auditor for instance; at most 365 days ahead); null: no end."},"locale":{"type":["string","null"],"enum":["en","fr","de","es","it","pt","nl","pl","sv","da","nb","fi","cs","ro","hu","el","tr","ja","zh","ar"],"description":"Language of the invitation email."},"expiresAt":{"type":"string","format":"date-time","description":"The link works until then: 7 days, or the end of a temporary access if sooner."},"expired":{"type":"boolean","description":"The link no longer works: revoke the invitation and invite again."},"inviterName":{"type":["string","null"],"description":"The member who invited (for a key: the member who created it); null: the Vigilo team or a former member."},"createdAt":{"type":"string","format":"date-time"}}},"Submission":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"requirementId":{"type":"string","format":"uuid"},"complianceTypeVersionId":{"type":"string","format":"uuid","description":"The version of the compliance type at the time: its fields give the keys of fieldValues."},"status":{"type":"string","enum":["pending_review","in_review","approved","rejected","superseded","withdrawn"],"description":"superseded: a later document replaced it; withdrawn: taken back before its review."},"lockVersion":{"type":"integer","description":"Changes with each step of its review (opened by a member, decided): send it with a decision (POST /submissions/{id}/approve or /reject)."},"channel":{"type":"string","enum":["portal","email_inbound","operator","client","api","import"],"description":"portal: sent by the third party; client: recorded by a member on its behalf (receivedVia, receivedOn); operator: recorded by Vigilo support; api: sent through the API (POST /submissions); import: loaded from a file; email_inbound: reserved."},"submittedBy":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["member","former_member","support","contact","api_key"],"description":"support: Vigilo staff acting on your request (no identity); contact: a person of the third party, through its portal link; api_key: sent through the API by that key."},"id":{"type":["string","null"],"format":"uuid","description":"User, contact or API key id; null for support."}}},"receivedVia":{"type":["string","null"],"enum":["email","mail","in_person","other",null],"description":"Recorded on the third party's behalf: how the document was received."},"receivedOn":{"type":["string","null"],"format":"date"},"fieldValues":{"type":"object","additionalProperties":true,"description":"Values entered with the document, by field key (dates as YYYY-MM-DD; an amount's currency under <key>.currency)."},"validFrom":{"type":["string","null"],"format":"date"},"validUntil":{"type":["string","null"],"format":"date"},"performedOn":{"type":["string","null"],"format":"date","description":"Date of the inspection or visit, for a periodic check."},"notes":{"type":["string","null"]},"reviewedAt":{"type":["string","null"],"format":"date-time"},"reviewedBy":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["member","former_member","support","contact","api_key"],"description":"support: Vigilo staff acting on your request (no identity); contact: a person of the third party, through its portal link; api_key: sent through the API by that key."},"id":{"type":["string","null"],"format":"uuid","description":"User, contact or API key id; null for support."}}},"rejectionReasonCode":{"type":["string","null"],"enum":["unreadable","expired","wrong_document","wrong_holder","insufficient_coverage","missing_pages","other",null]},"rejectionComment":{"type":["string","null"],"description":"Why it was refused, as the third party reads it."},"reviewComment":{"type":["string","null"],"description":"null unless include=review. Comment of the person who approved it (the second one in a four-eyes review); null unless approved. Internal: never shown to the third party."},"firstReviewedAt":{"type":["string","null"],"format":"date-time","description":"null unless include=review. Four-eyes review (reviewMode double): when the first person approved it, also while it waits for the second or once a new submission replaced it (superseded); null otherwise."},"firstReviewedBy":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["member","former_member","support","contact","api_key"],"description":"support: Vigilo staff acting on your request (no identity); contact: a person of the third party, through its portal link; api_key: sent through the API by that key."},"id":{"type":["string","null"],"format":"uuid","description":"User, contact or API key id; null for support."}},"description":"null unless include=review. The first person of a four-eyes review (support: Vigilo staff, no identity)."},"firstReviewComment":{"type":["string","null"],"description":"null unless include=review. Comment of the first person of a four-eyes review. Internal: never shown to the third party."},"checklist":{"type":["array","null"],"description":"null unless include=review. The checklist of its version (complianceTypeVersionId) as the reviewer ticked it; null: its version has none, nobody reviewed it (approved automatically, waiting), or it was refused.","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"object","additionalProperties":{"type":"string"},"description":"Text by language code (en, fr…): the languages the organization filled in."},"blocking":{"type":"boolean"},"checked":{"type":"boolean"}}}},"isCurrent":{"type":"boolean","description":"The requirement's current document (see currentSubmissionId)."},"files":{"type":"array","items":{"$ref":"#/components/schemas/SubmissionFile"}},"createdAt":{"type":"string","format":"date-time","description":"When it was sent."},"updatedAt":{"type":"string","format":"date-time"}}},"SubmissionFile":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","description":"File name as uploaded."},"mimeType":{"type":"string"},"sizeBytes":{"type":"integer"},"sha256":{"type":"string","description":"SHA-256 fingerprint of the content (hex), recorded at upload."},"scanStatus":{"type":"string","enum":["pending","clean","skipped"],"description":"clean: checked by the antivirus; skipped: not scanned. An infected file is refused at upload."},"activeContent":{"type":"boolean","description":"A PDF with scripts, launch actions or embedded files."},"uploadedAt":{"type":"string","format":"date-time"},"erased":{"type":"boolean","description":"The content was erased (GDPR erasure, or the document withdrawn with eraseFiles); name, size and fingerprint remain."},"contentUrl":{"type":["string","null"],"format":"uri","description":"Download address (same key, scope read:submissions); null once erased."},"storedCopy":{"type":["object","null"],"description":"The compressed copy Vigilo keeps instead of the uploaded bytes, 30 days after the decision on the deposit at the earliest, at once for a document reusing a file already compressed (photo turned into WebP, PDF optimized; never a signed PDF nor a PDF/A), null while the file is kept as uploaded. contentUrl serves this copy: compare its sha256 with the file received. The document's updatedAt moves when the copy replaces the uploaded bytes. name, mimeType, sizeBytes and sha256 above stay the uploaded file's (receipt, duplicate alert).","properties":{"name":{"type":"string","description":"The uploaded name with the copy's extension (photo.jpg → photo.webp)."},"mimeType":{"type":"string"},"sizeBytes":{"type":"integer"},"sha256":{"type":"string","description":"SHA-256 fingerprint of the copy (hex), the Repr-Digest of contentUrl."}}}}},"UploadedFile":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Pass it in fileIds of POST /submissions."},"name":{"type":"string","description":"The name given, cleaned (no path, no control character, 180 characters at most)."},"mimeType":{"type":"string","description":"The type read from the content (not from the name or Content-Type)."},"sizeBytes":{"type":"integer"},"sha256":{"type":"string","description":"SHA-256 fingerprint of the content (hex): compare it with yours."},"activeContent":{"type":"boolean","description":"A PDF with scripts, launch actions or embedded files (the reviewer is warned)."},"uploadedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time","description":"Deleted if no document uses it by then (24 hours)."}}},"WorkbookReport":{"type":"object","required":["committed","total","created","linked","existing","differing","errors","issues","sheets"],"properties":{"committed":{"type":"boolean","description":"true: everything was imported. false: a check, or a commit refused (nothing written)."},"total":{"type":"integer","description":"Data rows."},"created":{"type":"integer"},"linked":{"type":"integer","description":"Known third parties linked to a site or a unit."},"existing":{"type":"integer","description":"Rows already in Vigilo (left as they are)."},"updated":{"type":"integer","description":"With update=true: known portfolios, sites, units and equipment whose filled cells were applied."},"differing":{"type":"integer","description":"Known rows whose record differs from the file and were not updated (third parties never are)."},"errors":{"type":"integer","description":"Rows with an error: a commit writes nothing while it is above 0."},"issues":{"type":"array","items":{"type":"object","required":["code","message"],"properties":{"sheet":{"type":"string"},"code":{"type":"string","description":"Error code (see the guide's list of errors)."},"message":{"type":"string","description":"The English sentence, as the import screen words it (« « Igloo » is not in the list (sheet « Lists »). »)."},"params":{"type":"object","additionalProperties":true}}},"description":"Workbook remarks: sheet not recognized (imp.unknownSheet), sheet given twice (imp.duplicateSheet)."},"sheets":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["portfolios","sites","units","parties","assets","requirements","team","contacts"],"description":"team: the Team sheet, one invitation per row (scope write:members). contacts: the Third-party contacts sheet, one contact per row under a party named by its name, registration number, external reference or id; a known contact (same id, else same email for that party, else same name without email) is existing, updated with update=true."},"sheet":{"type":"string","description":"The sheet's name in the file."},"unknownColumns":{"type":"array","items":{"type":"string"},"description":"Headers that match no field: ignored."},"issues":{"type":"array","items":{"type":"object","required":["code","message"],"properties":{"sheet":{"type":"string"},"code":{"type":"string","description":"Error code (see the guide's list of errors)."},"message":{"type":"string","description":"The English sentence, as the import screen words it (« « Igloo » is not in the list (sheet « Lists »). »)."},"params":{"type":"object","additionalProperties":true}}},"description":"A mandatory column missing (imp.missingColumn)."},"customFields":{"type":"object","additionalProperties":{"type":"string"},"description":"cf:<key> -> label of the organization's custom fields of this kind."},"total":{"type":"integer","description":"Data rows."},"created":{"type":"integer"},"linked":{"type":"integer","description":"Known third parties linked to a site or a unit."},"existing":{"type":"integer","description":"Rows already in Vigilo (left as they are)."},"updated":{"type":"integer","description":"With update=true: known portfolios, sites, units and equipment whose filled cells were applied."},"differing":{"type":"integer","description":"Known rows whose record differs from the file and were not updated (third parties never are)."},"errors":{"type":"integer","description":"Rows with an error: a commit writes nothing while it is above 0."},"rows":{"type":"array","description":"The rows that need attention (everything but a plain creation), 500 at most per sheet.","items":{"type":"object","properties":{"line":{"type":"integer","description":"Line of the sheet (header = 1)."},"status":{"type":"string","enum":["created","linked","existing","updated","error"],"description":"updated: only with update=true (a known row whose differences were applied)."},"label":{"type":"string"},"issues":{"type":"array","items":{"type":"object","required":["code","message"],"properties":{"field":{"type":"string","description":"The field of the column (its key); empty for the whole row."},"code":{"type":"string","description":"Error code (see the guide's list of errors)."},"message":{"type":"string","description":"The English sentence, as the import screen words it (« « Igloo » is not in the list (sheet « Lists »). »)."},"params":{"type":"object","additionalProperties":true},"value":{"type":"string","description":"The cell as received (first 100 characters)."},"max":{"type":"integer","description":"validation.tooLong: the maximum length."},"length":{"type":"integer","description":"validation.tooLong: the length received."}}}},"warnings":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"params":{"type":"object","additionalProperties":true,"description":"Values of the sentence (count, column, subject…). The name of another third party only for a key with read:parties."},"field":{"type":"string","description":"Column the warning is about, when there is one (imp.subjectColumnIgnored)."}}}},"partyId":{"type":"string","format":"uuid","description":"A known third party: its id."}}}}}}},"firstRequests":{"type":["object","null"],"description":"The first requests the created requirements will send (active rules). null: none.","additionalProperties":true},"importId":{"type":["string","null"],"format":"uuid","description":"The import written (committed true and something created): undo it with POST /imports/{id}/undo within 30 days. null: a check, or nothing created."},"invitations":{"type":["object","null"],"description":"The invitation emails of the Team sheet, sent once the workbook is imported. null: none sent (a check, or no new invitation). failed: the addresses whose invitation was created but not emailed; resend it from Settings › Members (or POST /api/v1/invitations after revoking it).","properties":{"sent":{"type":"integer"},"failed":{"type":"array","items":{"type":"string","format":"email"}}}}}},"Import":{"type":"object","required":["id","kind","filename","createdAt","createdBy","counts","undoable","undoUntil","undoneAt","undoCounts"],"properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["workbook","portfolios","sites","units","parties","assets","requirements","contacts"],"description":"workbook: the starter workbook (screen or POST /imports/workbook); otherwise the screen's import of one kind."},"filename":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["member","former_member","support","system","contact","api_key"],"description":"Who imported, as the journal's actor.type (no name here: the journal's import.completed event names them, scope read:audit)."}}},"counts":{"type":"object","properties":{"total":{"type":"integer"},"created":{"type":"integer"},"linked":{"type":"integer"},"existing":{"type":"integer"},"updated":{"type":"integer"}}},"undoable":{"type":"boolean","description":"true: it created something, is not undone, and undoUntil has not passed (while the organization is suspended the undo still answers 422 org.suspended, and undoImpact is null)."},"undoUntil":{"type":"string","format":"date-time","description":"An import is undone within 30 days, once."},"undoneAt":{"type":["string","null"],"format":"date-time"},"undoCounts":{"type":["object","null"],"description":"What the undo archived (requirements: closed) by type; keptPortfolios: created portfolios kept because they hold another site; releasedKeys: codes and references given the suffix ~… so that the corrected file loads at once. null: not undone.","properties":{"portfolios":{"type":"integer"},"sites":{"type":"integer"},"units":{"type":"integer"},"assets":{"type":"integer"},"parties":{"type":"integer"},"relationships":{"type":"integer"},"contacts":{"type":"integer"},"requirements":{"type":"integer"},"keptPortfolios":{"type":"integer"},"releasedKeys":{"type":"integer"}}}}},"ImportDetail":{"type":"object","required":["id","kind","filename","createdAt","createdBy","counts","undoable","undoUntil","undoneAt","undoCounts","undoImpact"],"properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["workbook","portfolios","sites","units","parties","assets","requirements","contacts"],"description":"workbook: the starter workbook (screen or POST /imports/workbook); otherwise the screen's import of one kind."},"filename":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["member","former_member","support","system","contact","api_key"],"description":"Who imported, as the journal's actor.type (no name here: the journal's import.completed event names them, scope read:audit)."}}},"counts":{"type":"object","properties":{"total":{"type":"integer"},"created":{"type":"integer"},"linked":{"type":"integer"},"existing":{"type":"integer"},"updated":{"type":"integer"}}},"undoable":{"type":"boolean","description":"true: it created something, is not undone, and undoUntil has not passed (while the organization is suspended the undo still answers 422 org.suspended, and undoImpact is null)."},"undoUntil":{"type":"string","format":"date-time","description":"An import is undone within 30 days, once."},"undoneAt":{"type":["string","null"],"format":"date-time"},"undoCounts":{"type":["object","null"],"description":"What the undo archived (requirements: closed) by type; keptPortfolios: created portfolios kept because they hold another site; releasedKeys: codes and references given the suffix ~… so that the corrected file loads at once. null: not undone.","properties":{"portfolios":{"type":"integer"},"sites":{"type":"integer"},"units":{"type":"integer"},"assets":{"type":"integer"},"parties":{"type":"integer"},"relationships":{"type":"integer"},"contacts":{"type":"integer"},"requirements":{"type":"integer"},"keptPortfolios":{"type":"integer"},"releasedKeys":{"type":"integer"}}},"undoImpact":{"type":["object","null"],"description":"What an undo would reach, as the screen's dialog says; null once it may no longer be undone (or while the organization is suspended).","properties":{"active":{"type":"object","description":"What the import created that is still active (requirements: still open), by type.","properties":{"portfolios":{"type":"integer"},"sites":{"type":"integer"},"units":{"type":"integer"},"assets":{"type":"integer"},"parties":{"type":"integer"},"relationships":{"type":"integer"},"contacts":{"type":"integer"},"requirements":{"type":"integer"}}},"requirements":{"type":"integer","description":"Open requirements the undo closes: those of the elements it archives and those of the Requirements sheet."},"contacted":{"type":"integer","description":"Created third parties already sent an email (an email sent is not recalled)."},"submissions":{"type":"integer","description":"Documents already sent on those requirements: kept, archived with them."},"updated":{"type":"integer","description":"Rows the import updated: never undone (the previous values are in each record's history)."}}}}},"Export":{"type":"object","required":["id","status","requestedBy","createdAt","startedAt","completedAt","expiresAt","sizeBytes","sha256","fileName","error","downloadUrl"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pending","running","done","failed","expired"],"description":"pending: waiting for the builder (it runs every 5 minutes); running; done: downloadable at downloadUrl until expiresAt; failed: see error; expired: deleted, request a new one."},"requestedBy":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["member","apiKey","platform"]},"id":{"type":"string","format":"uuid","description":"The key (apiKey only)."},"name":{"type":"string","description":"The key's name (apiKey only)."}}},"createdAt":{"type":"string","format":"date-time"},"startedAt":{"type":["string","null"],"format":"date-time"},"completedAt":{"type":["string","null"],"format":"date-time"},"expiresAt":{"type":["string","null"],"format":"date-time","description":"48 hours after it was built when a key requested it, 7 days when a member did."},"sizeBytes":{"type":["integer","null"],"description":"Size of the ZIP."},"sha256":{"type":["string","null"],"description":"SHA-256 (hex) of the ZIP: compare it with the file received (also the ETag of the download)."},"fileName":{"type":["string","null"]},"error":{"type":["object","null"],"required":["code","message"],"properties":{"code":{"type":"string","description":"imp.exportTooLarge: beyond 64 000 files or 4 GiB; contact the support."},"message":{"type":"string"}}},"downloadUrl":{"type":["string","null"],"format":"uri","description":"Where to GET the ZIP, with the same key (done only)."}}},"AuditEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"occurredAt":{"type":"string","format":"date-time","description":"When the change was recorded (UTC, to the microsecond): the start of its transaction. The list follows the commit order, so it may step back by a few seconds."},"action":{"type":"string","description":"What happened, as entity.verb (requirement.status_changed, submission.approved, api_key.created…). New actions appear over time."},"category":{"type":"string","enum":["security","reference","compliance","review","reminder","administration"],"description":"Group of the action, as the journal screen filters it."},"entityType":{"type":"string","description":"Kind of the record changed (requirement, party, site, relationship, submission, api_key, organization…)."},"entityId":{"type":["string","null"],"format":"uuid"},"entityLabel":{"type":["string","null"],"description":"Name of the portfolio, site, unit, equipment, party or contact, when the event is about one."},"actor":{"type":"object","properties":{"type":{"type":"string","enum":["member","former_member","support","system","contact","api_key","anonymous"],"description":"support: Vigilo staff acting on your request (no identity); contact: a third party through its portal link; system: a scheduled job; anonymous: nobody signed in (a failed sign-in, whose entity is the account aimed at)."},"id":{"type":["string","null"],"format":"uuid","description":"User, contact or API key id; null for support, system and anonymous."},"name":{"type":["string","null"],"description":"Member's name, or the API key's name and prefix."},"email":{"type":["string","null"],"description":"Current members only."}}},"viaSupport":{"type":"boolean","description":"Done by Vigilo support while acting in your organization."},"ip":{"type":["string","null"],"description":"Address of the request, recorded on the sign-ins of the members, on every action of an API key and on the sensitive actions of a member (exports, API keys, roles and removals, ownership, closure); null otherwise. Erased after 12 months."},"requestId":{"type":["string","null"]},"changes":{"type":["object","null"],"additionalProperties":true,"description":"before / after values of the fields that changed (never a secret)."}}},"ComplianceAtDate":{"type":"object","properties":{"date":{"type":"string","format":"date"},"time":{"type":["string","null"],"description":"HH:MM asked; null: the end of the day."},"compliance":{"type":"object","description":"The state at that instant, counted as the party's `compliance` (closed requirements left out, waived ones by today's setting).","properties":{"status":{"type":"string","enum":["non_compliant","pending","compliant","none"]},"applicable":{"type":"integer"},"compliant":{"type":"integer"},"nonCompliant":{"type":"integer"},"pending":{"type":"integer"}}},"addedLater":{"type":"integer","description":"Requirements of the same third party / site created after the instant and still followed (not counted)."},"requirements":{"type":"array","description":"Inbound requirements that existed at the instant and were not closed then, worst bucket first.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"complianceTypeId":{"type":"string","format":"uuid"},"typeCode":{"type":"string"},"typeName":{"type":"object","additionalProperties":{"type":"string"},"description":"Text by language code (en, fr…): the languages the organization filled in."},"subjectType":{"type":"string","enum":["party","site","unit","asset","organization"]},"subjectId":{"type":"string","format":"uuid"},"partyId":{"type":["string","null"],"format":"uuid"},"siteId":{"type":["string","null"],"format":"uuid"},"relationshipId":{"type":["string","null"],"format":"uuid"},"status":{"type":"string","enum":["not_requested","requested","submitted","in_review","rejected","compliant","expiring_soon","overdue","expired","waived","closed"],"description":"The status at the instant, from the audit trail."},"isBlocked":{"type":"boolean","description":"Blocked by an open finding at the instant."},"statusSince":{"type":["string","null"],"format":"date-time","description":"When that status was recorded; null: before the oldest event kept."},"currentStatus":{"type":"string","enum":["not_requested","requested","submitted","in_review","rejected","compliant","expiring_soon","overdue","expired","waived","closed"]},"currentBlocked":{"type":"boolean"},"evidence":{"type":["object","null"],"description":"The approved document whose validity contains the date: one approved before the instant first, else the first approved after it. null: none.","properties":{"submissionId":{"type":"string","format":"uuid"},"validFrom":{"type":["string","null"],"format":"date"},"validUntil":{"type":["string","null"],"format":"date"},"receivedOn":{"type":"string","format":"date"},"approvedAt":{"type":"string","format":"date-time"},"approvedAfterDate":{"type":"boolean","description":"true: valid on that date, but approved after the instant (it was not on file then)."}}}}}}}},"Webhook":{"type":"object","required":["id","url","description","events","active","createdAt","previousSecretExpiresAt"],"properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"type":["string","null"]},"events":{"type":"array","items":{"type":"string","enum":["requirement.status_changed","submission.created","submission.reviewed","requirement.created","requirement.contested","requirement.message_received","relationship.status_changed","party.merged","party.compliance_changed","finding.created","finding.status_changed","organization.restored"]}},"active":{"type":"boolean","description":"false: paused (PATCH /api/v1/webhooks/{id} active), disabled after repeated failures (PATCH it with active true once the receiver is fixed, or enable it in Settings > API), or because the key that subscribed it was revoked or has expired (subscribe again with an active key)."},"createdAt":{"type":"string","format":"date-time"},"previousSecretExpiresAt":{"type":["string","null"],"format":"date-time","description":"Until then, the secret replaced by the last renewal still signs the deliveries next to the current one; null when there is none (POST /api/v1/webhooks/{id}/rotate-secret)."}}},"WebhookCreated":{"type":"object","required":["id","url","description","events","active","createdAt","previousSecretExpiresAt","secret"],"properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string"},"description":{"type":["string","null"]},"events":{"type":"array","items":{"type":"string","enum":["requirement.status_changed","submission.created","submission.reviewed","requirement.created","requirement.contested","requirement.message_received","relationship.status_changed","party.merged","party.compliance_changed","finding.created","finding.status_changed","organization.restored"]}},"active":{"type":"boolean","description":"false: paused (PATCH /api/v1/webhooks/{id} active), disabled after repeated failures (PATCH it with active true once the receiver is fixed, or enable it in Settings > API), or because the key that subscribed it was revoked or has expired (subscribe again with an active key)."},"createdAt":{"type":"string","format":"date-time"},"previousSecretExpiresAt":{"type":["string","null"],"format":"date-time","description":"Until then, the secret replaced by the last renewal still signs the deliveries next to the current one; null when there is none (POST /api/v1/webhooks/{id}/rotate-secret)."},"secret":{"type":"string","description":"Signing secret whsec_…, given this once (see x-webhooks)."}}}}},"webhooks":{"requirement.status_changed":{"post":{"summary":"Sent to the endpoints subscribed to requirement.status_changed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["requirement.status_changed"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["requirementId","status","previousStatus","direction","isBlocked"],"properties":{"requirementId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["not_requested","requested","submitted","in_review","rejected","compliant","expiring_soon","overdue","expired","waived","closed"]},"previousStatus":{"type":"string","enum":["not_requested","requested","submitted","in_review","rejected","compliant","expiring_soon","overdue","expired","waived","closed"],"description":"Equal to status when only isBlocked changed (a finding was raised, resolved or discarded)."},"direction":{"type":"string","enum":["inbound","outbound"],"description":"inbound (collected) or outbound (produced and sent by the organization)."},"isBlocked":{"type":"boolean","description":"An open finding blocks the requirement's compliance (its compliance type says which findings do): read it with status."}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}},"submission.created":{"post":{"summary":"Sent to the endpoints subscribed to submission.created.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["submission.created"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["submissionId","requirementId","direction"],"properties":{"submissionId":{"type":"string","format":"uuid"},"requirementId":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["inbound","outbound"],"description":"inbound (collected) or outbound (produced and sent by the organization)."}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}},"submission.reviewed":{"post":{"summary":"Sent to the endpoints subscribed to submission.reviewed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["submission.reviewed"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["submissionId","requirementId","decision","direction"],"properties":{"submissionId":{"type":"string","format":"uuid"},"requirementId":{"type":"string","format":"uuid"},"decision":{"type":"string","enum":["approved","rejected"]},"direction":{"type":"string","enum":["inbound","outbound"],"description":"inbound (collected) or outbound (produced and sent by the organization)."}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}},"requirement.created":{"post":{"summary":"Sent to the endpoints subscribed to requirement.created.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["requirement.created"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["requirementId","status","source","direction"],"properties":{"requirementId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["not_requested","requested","submitted","in_review","rejected","compliant","expiring_soon","overdue","expired","waived","closed"]},"source":{"type":"string","enum":["rule","manual","import","api"],"description":"How it was created: by hand on the screen (manual), by an import, through the API, or by an assignment rule."},"direction":{"type":"string","enum":["inbound","outbound"],"description":"inbound (collected) or outbound (produced and sent by the organization)."}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}},"requirement.contested":{"post":{"summary":"Sent to the endpoints subscribed to requirement.contested.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["requirement.contested"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["requirementId","direction"],"properties":{"requirementId":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["inbound","outbound"],"description":"inbound (collected) or outbound (produced and sent by the organization)."}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}},"requirement.message_received":{"post":{"summary":"Sent to the endpoints subscribed to requirement.message_received.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["requirement.message_received"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["requirementId","direction"],"properties":{"requirementId":{"type":"string","format":"uuid"},"direction":{"type":"string","enum":["inbound","outbound"],"description":"inbound (collected) or outbound (produced and sent by the organization)."}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}},"relationship.status_changed":{"post":{"summary":"Sent to the endpoints subscribed to relationship.status_changed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["relationship.status_changed"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["relationshipId","partyId","status","previousStatus"],"properties":{"relationshipId":{"type":"string","format":"uuid"},"partyId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["upcoming","active","ended"]},"previousStatus":{"type":"string","enum":["upcoming","active","ended"]}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}},"party.merged":{"post":{"summary":"Sent to the endpoints subscribed to party.merged.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["party.merged"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["partyId","mergedPartyId"],"properties":{"partyId":{"type":"string","format":"uuid","description":"The party kept."},"mergedPartyId":{"type":"string","format":"uuid","description":"The duplicate merged into it: this id no longer exists."}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}},"party.compliance_changed":{"post":{"summary":"Sent to the endpoints subscribed to party.compliance_changed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["party.compliance_changed"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["partyId","status","previousStatus"],"properties":{"partyId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["non_compliant","pending","compliant","none"]},"previousStatus":{"type":"string","enum":["non_compliant","pending","compliant","none"]}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}},"finding.created":{"post":{"summary":"Sent to the endpoints subscribed to finding.created.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["finding.created"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["findingId","requirementId","severity","status","direction"],"properties":{"findingId":{"type":"string","format":"uuid"},"requirementId":{"type":"string","format":"uuid"},"severity":{"type":"string","enum":["critical","major","minor","observation"]},"status":{"type":"string","enum":["open","in_progress","resolved","verified","wont_fix"]},"direction":{"type":"string","enum":["inbound","outbound"],"description":"inbound (collected) or outbound (produced and sent by the organization)."}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}},"finding.status_changed":{"post":{"summary":"Sent to the endpoints subscribed to finding.status_changed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["finding.status_changed"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["findingId","requirementId","severity","status","previousStatus","direction"],"properties":{"findingId":{"type":"string","format":"uuid"},"requirementId":{"type":"string","format":"uuid"},"severity":{"type":"string","enum":["critical","major","minor","observation"]},"status":{"type":"string","enum":["open","in_progress","resolved","verified","wont_fix"]},"previousStatus":{"type":"string","enum":["open","in_progress","resolved","verified","wont_fix"]},"direction":{"type":"string","enum":["inbound","outbound"],"description":"inbound (collected) or outbound (produced and sent by the organization)."}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}},"organization.restored":{"post":{"summary":"Sent to the endpoints subscribed to organization.restored.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["organization.restored"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["restoredTo","kind"],"properties":{"restoredTo":{"type":"string","format":"date-time","description":"The night of the back up the organization's data went back to: what was written since is gone, and the rows it removed are seen by no updatedSince. Synchronize everything again."},"kind":{"type":"string","enum":["restore","undo"],"description":"undo: back to the state just before a restoration (« Undo the restoration »)."}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}},"webhook.test":{"post":{"summary":"Sent on demand from the settings screen, whatever the subscriptions.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type","version","timestamp","data"],"properties":{"type":{"type":"string","enum":["webhook.test"]},"version":{"type":"integer","enum":[1]},"timestamp":{"type":"string","format":"date-time","description":"When the event was recorded."},"data":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}}}}}}},"responses":{"2XX":{"description":"Received. Any other answer, or none within 10 s, is retried."}}}}},"x-webhooks":{"events":["requirement.status_changed","submission.created","submission.reviewed","requirement.created","requirement.contested","requirement.message_received","relationship.status_changed","party.merged","party.compliance_changed","finding.created","finding.status_changed","organization.restored"],"version":1,"body":"{ type, version, timestamp, data }","signature":"Standard Webhooks (webhook-id, webhook-timestamp, webhook-signature; HMAC-SHA256, secret whsec_…). After a secret renewal, webhook-signature lists two signatures for 24 hours (the new secret's first): accept the request when one of them matches."}}