{
  "x-generator": "NSwag v14.7.1.0 (NJsonSchema v11.6.1.0 (Newtonsoft.Json v13.0.0.0))",
  "openapi": "3.0.0",
  "info": {
    "title": "Twarz API - Documentation",
    "description": "The operations a company's system calls with its API key: create petitions, read what the person shared, and manage the webhooks that report each outcome.",
    "version": "2.2.0"
  },
  "servers": [
    {
      "url": "/api"
    }
  ],
  "paths": {
    "/v1/biometric/records/shared": {
      "get": {
        "tags": [
          "Records"
        ],
        "summary": "Read shared data",
        "description": "Returns what a member shared with the caller's company by approving a petition: one section per resource named in include (biographic, document, portrait, capture), each of which the grant token must list; the images come back base64-encoded with their media type. Requires the grant token from that petition's sharedData in the X-Grant-Token header; the grant token expires shortly after it is issued.",
        "operationId": "DorTwarzApiBiometricFeaturesRecordsGetSharedRecordGetSharedRecordEndpoint",
        "parameters": [
          {
            "name": "include",
            "in": "query",
            "description": "The resources to read, comma-separated, as named in SharedRecordResources and listed in the\npetition's sharedData.resources. Required. Every one must be listed by the grant token, or the whole\nread is refused. Bound from the query string.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The sections asked for",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SharedRecordResponse"
                }
              }
            }
          },
          "400": {
            "description": "No grant token, or include is empty or names a resource this read does not serve"
          },
          "403": {
            "description": "The grant token has expired (GRANT_TOKEN_EXPIRED): read the petition again for a fresh one"
          },
          "404": {
            "description": "The grant token does not open every resource asked for to the caller, or there is no data behind it"
          },
          "401": {
            "description": "Unauthorized"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/tenant/webhooks/{id}/verify": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Verify a webhook subscription's endpoint",
        "description": "POSTs a signed `endpoint.verification` ping carrying a one-time challenge to the subscription's URL. The endpoint passes by answering 2xx and echoing the challenge — either as `{\"challenge\":\"…\"}` or as the bare value — at which point the subscription goes Pending → Active and deliveries begin. An endpoint that fails is reported in the 200 response body (`verified: false` plus the reason); the subscription stays Pending and can be retried.",
        "operationId": "DorTwarzApiTenantFeaturesWebhooksVerifyWebhookSubscriptionVerifyWebhookSubscriptionEndpoint",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The subscription id to verify.",
            "schema": {
              "type": "string",
              "format": "guid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Handshake attempted (see `verified`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerifyWebhookSubscriptionResponse"
                }
              }
            }
          },
          "404": {
            "description": "Subscription not found"
          },
          "409": {
            "description": "Subscription is paused — resume it instead of verifying"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/tenant/webhooks/{id}/resume": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Resume a webhook subscription",
        "description": "Resumes deliveries for a paused subscription.",
        "operationId": "DorTwarzApiTenantFeaturesWebhooksResumeWebhookSubscriptionResumeWebhookSubscriptionEndpoint",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The subscription id to resume.",
            "schema": {
              "type": "string",
              "format": "guid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Subscription resumed"
          },
          "404": {
            "description": "Subscription not found"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/tenant/webhooks/{id}/pause": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Pause a webhook subscription",
        "description": "Pauses deliveries for a subscription until it is resumed.",
        "operationId": "DorTwarzApiTenantFeaturesWebhooksPauseWebhookSubscriptionPauseWebhookSubscriptionEndpoint",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The subscription id to pause.",
            "schema": {
              "type": "string",
              "format": "guid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Subscription paused"
          },
          "404": {
            "description": "Subscription not found"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/tenant/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List the company's webhook subscriptions",
        "description": "Returns the company's webhook subscriptions (config only — the secret is never returned).",
        "operationId": "DorTwarzApiTenantFeaturesWebhooksListWebhookSubscriptionsListWebhookSubscriptionsEndpoint",
        "responses": {
          "200": {
            "description": "Subscriptions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListWebhookSubscriptionsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Register a webhook subscription",
        "description": "Registers a webhook subscription for the authenticated company. The HMAC signing secret is returned once in the response and never again. The subscription starts Pending until verified.",
        "operationId": "DorTwarzApiTenantFeaturesWebhooksCreateWebhookSubscriptionCreateWebhookSubscriptionEndpoint",
        "requestBody": {
          "x-name": "CreateWebhookSubscriptionRequest",
          "description": "",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookSubscriptionRequest"
              }
            }
          },
          "required": true,
          "x-position": 1
        },
        "responses": {
          "201": {
            "description": "Subscription created (secret returned once)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateWebhookSubscriptionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/tenant/webhooks/events": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List subscribable webhook event types",
        "description": "Returns the catalogue of event types a company may subscribe a webhook to.",
        "operationId": "DorTwarzApiTenantFeaturesWebhooksListWebhookEventsListWebhookEventsEndpoint",
        "responses": {
          "200": {
            "description": "Event catalogue",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListWebhookEventsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/tenant/webhooks/{id}": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Read one of the company's webhook subscriptions",
        "description": "Returns one of the company's webhook subscriptions (config only — the secret is never returned). Its status says whether deliveries are flowing: a subscription is paused automatically after repeated failed deliveries.",
        "operationId": "DorTwarzApiTenantFeaturesWebhooksGetWebhookSubscriptionGetWebhookSubscriptionEndpoint",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The subscription id.",
            "schema": {
              "type": "string",
              "format": "guid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetWebhookSubscriptionResponse"
                }
              }
            }
          },
          "404": {
            "description": "No such subscription for this company"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Delete a webhook subscription",
        "description": "Soft-deletes a subscription; it stops receiving deliveries. Irreversible.",
        "operationId": "DorTwarzApiTenantFeaturesWebhooksDeleteWebhookSubscriptionDeleteWebhookSubscriptionEndpoint",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The subscription id to delete.",
            "schema": {
              "type": "string",
              "format": "guid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Subscription deleted"
          },
          "404": {
            "description": "Subscription not found"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/coreo/templates": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "List the company's petition templates",
        "description": "Returns the company's active petition templates — the shapes petitions are built from.",
        "operationId": "DorTwarzApiCoreoFeaturesTemplatesListPetitionTemplatesListPetitionTemplatesEndpoint",
        "responses": {
          "200": {
            "description": "Templates",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListPetitionTemplatesResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/coreo/templates/{id}": {
      "get": {
        "tags": [
          "Templates"
        ],
        "summary": "Inspect a petition template",
        "description": "Returns the shape of a single petition template the company can build a petition from.",
        "operationId": "DorTwarzApiCoreoFeaturesTemplatesGetPetitionTemplateGetPetitionTemplateEndpoint",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The template id.",
            "schema": {
              "type": "string",
              "format": "guid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Template",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PetitionTemplateResponse"
                }
              }
            }
          },
          "404": {
            "description": "Template not found"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/coreo/petitions/{petitionId}/requirements/{requirementId}/attach": {
      "post": {
        "tags": [
          "Petitions"
        ],
        "summary": "Attach a to-sign document's file",
        "description": "Stores (or replaces) the file for a ToSign document in a petition raised by the calling company.",
        "operationId": "DorTwarzApiCoreoFeaturesPetitionsUploadProviderDocumentUploadProviderDocumentEndpoint",
        "parameters": [
          {
            "name": "petitionId",
            "in": "path",
            "required": true,
            "description": "The owning petition, which must belong to the calling company.",
            "schema": {
              "type": "string",
              "format": "guid"
            }
          },
          {
            "name": "requirementId",
            "in": "path",
            "required": true,
            "description": "The to-sign obligation being furnished.",
            "schema": {
              "type": "string",
              "format": "guid"
            }
          }
        ],
        "requestBody": {
          "x-name": "UploadProviderDocumentRequest",
          "description": "",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadProviderDocumentRequest"
              }
            }
          },
          "required": true,
          "x-position": 1
        },
        "responses": {
          "200": {
            "description": "File stored",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadProviderDocumentResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "404": {
            "description": "Petition or requirement not found / not raised by this company"
          },
          "422": {
            "description": "Petition not actionable, wrong document kind, or already signed"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/coreo/petitions": {
      "get": {
        "tags": [
          "Petitions"
        ],
        "summary": "List the company's petitions",
        "description": "A page of the authenticated company's petitions, newest first, optionally narrowed to one lifecycle state and searched by the person they are addressed to. Rows report the effective status, so a petition past its deadline reads Timeout whether or not the expiry sweep has flipped it yet.",
        "operationId": "DorTwarzApiCoreoFeaturesPetitionsListPetitionsListPetitionsEndpoint",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "Lifecycle state to include: Pending, Delivered, Approved, Rejected or\nTimeout. Omit for every state. An unrecognised value is refused rather than ignored.\nFiltered on the effective state, the same one the rows report — so Timeout includes a\npetition whose deadline has passed but whose row the expiry sweep has not flipped yet, and\nDelivered excludes it.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Every word of three characters or more must appear, in any case, in one of: person name, person username or document. A term with no such word matches nobody.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": true,
            "description": "1-based page number.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": true,
            "description": "Rows per page, clamped to 100.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The requested page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListPetitionsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Unrecognised status filter"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      },
      "post": {
        "tags": [
          "Petitions"
        ],
        "summary": "Create a petition targeting a user",
        "description": "Creates a petition from one of the company's templates, on behalf of the authenticated company, and delivers it. The template fixes what is asked for: its data, assurance, expiry and documents. The response's missingCategories lists the requested data the person does not hold today; the petition is sent anyway, and they cannot approve it until they supply that data.",
        "operationId": "DorTwarzApiCoreoFeaturesPetitionsCreatePetitionCreatePetitionEndpoint",
        "requestBody": {
          "x-name": "CreatePetitionRequest",
          "description": "",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePetitionRequest"
              }
            }
          },
          "required": true,
          "x-position": 1
        },
        "responses": {
          "201": {
            "description": "Petition created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatePetitionResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation failed"
          },
          "404": {
            "description": "Target user not found, or no such template for this company"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/coreo/petitions/{id}/provider": {
      "get": {
        "tags": [
          "Petitions"
        ],
        "summary": "Read a petition as the company that raised it",
        "description": "Returns what was asked, who asked and how it turned out. Deliberately excludes the resolution checklist the target's own read carries — the requester never sees the capability gap (ADR-0005 §7).",
        "operationId": "DorTwarzApiCoreoFeaturesPetitionsGetProviderPetitionGetProviderPetitionEndpoint",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "The petition id.",
            "schema": {
              "type": "string",
              "format": "guid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The petition",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderPetitionResponse"
                }
              }
            }
          },
          "404": {
            "description": "No such petition for this company"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/coreo/petitions/{petitionId}/requirements/{requirementId}/provider": {
      "get": {
        "tags": [
          "Petitions"
        ],
        "summary": "Read a signed document as the company that asked for it",
        "description": "Returns the to-sign obligation's instrument, a short-lived URL for it, and — once the member has signed — when they signed, which version and hash the signature attests to, and the hand-drawn stroke when one was captured. A member-supplied file is described but not served: that one is theirs, and reading it goes through the member surface.",
        "operationId": "DorTwarzApiCoreoFeaturesPetitionsGetProviderDocumentGetProviderDocumentEndpoint",
        "parameters": [
          {
            "name": "petitionId",
            "in": "path",
            "required": true,
            "description": "The owning petition.",
            "schema": {
              "type": "string",
              "format": "guid"
            }
          },
          {
            "name": "requirementId",
            "in": "path",
            "required": true,
            "description": "The obligation to read.",
            "schema": {
              "type": "string",
              "format": "guid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The obligation, and the instrument when there is one",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderDocumentResponse"
                }
              }
            }
          },
          "404": {
            "description": "No such petition for this company, no such requirement on it, or a relationship that has been archived — archived is member-only"
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    },
    "/v1/coreo/access/catalog": {
      "get": {
        "tags": [
          "Access"
        ],
        "summary": "The data-access catalog",
        "description": "Every data-category code with its family and whether it can be requested, plus every named bundle with the codes it stands for.",
        "operationId": "DorTwarzApiCoreoFeaturesAccessGetDataCatalogGetDataCatalogEndpoint",
        "responses": {
          "200": {
            "description": "Catalog",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataCatalogResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          },
          "403": {
            "description": "Forbidden"
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "SharedRecordResponse": {
        "type": "object",
        "description": "What a member shared with a company, one section per resource the read asked for (ADR-0027).\n            \nA section is set exactly when its resource was in include; the rest stay null. A resource the\ngrant token does not list is never a missing section — it refuses the whole read — so a null here always\nmeans \"not asked for\", never \"not allowed\".",
        "additionalProperties": false,
        "properties": {
          "biographic": {
            "description": "Name, date of birth, sex and nationality; set when biographic was included.",
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/SharedBiographic"
              }
            ]
          },
          "document": {
            "description": "The identity document's fields; set when document was included.",
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/SharedDocument"
              }
            ]
          },
          "portrait": {
            "description": "The verified portrait — the enrollment selfie; set when portrait was included.",
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/SharedImage"
              }
            ]
          },
          "capture": {
            "description": "The capture of the verified document; set when capture was included.",
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/SharedImage"
              }
            ]
          }
        }
      },
      "SharedBiographic": {
        "type": "object",
        "description": "The biographic fields a member shared with a company: what the catalog promises for B — name,\ndate of birth, sex and nationality — and nothing else.\n            \nLeast privilege by construction: the snapshot holds more (place of birth, the document identifiers),\nand none of it is here, because the member consented to these four and a field added to the snapshot\nlater must not start leaking through this read without somebody deciding it should.",
        "additionalProperties": false,
        "required": [
          "firstName",
          "lastName",
          "dateOfBirth",
          "gender",
          "nationality"
        ],
        "properties": {
          "firstName": {
            "type": "string",
            "description": "Given names, as read off the verified document."
          },
          "lastName": {
            "type": "string",
            "description": "Surnames, as read off the verified document."
          },
          "dateOfBirth": {
            "type": "string",
            "description": "Date of birth.",
            "format": "date"
          },
          "gender": {
            "description": "Sex as reported on the verified document.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Gender"
              }
            ]
          },
          "nationality": {
            "type": "string",
            "description": "Nationality (ISO 3166-1 alpha-3) of the holder."
          }
        }
      },
      "Gender": {
        "type": "integer",
        "description": "Gender",
        "x-enumNames": [
          "None",
          "Male",
          "Female"
        ],
        "enum": [
          0,
          1,
          2
        ]
      },
      "SharedDocument": {
        "type": "object",
        "description": "The identity-document fields a member shared with a company: what the catalog promises for D —\ntype, number, issuer and dates.\n            \nThe values come from the document's chip: a member holds D only after an NFC verification, and a\npetition can only be approved with codes the member actually holds.",
        "additionalProperties": false,
        "required": [
          "documentNumber",
          "issuingState",
          "documentExpiry"
        ],
        "properties": {
          "documentType": {
            "type": "string",
            "description": "What kind of document it is, as the vendor reports it (e.g. Identity Card, Passport,\nor the single-letter code a chip read gives). Null on records enrolled before it was stored.",
            "nullable": true
          },
          "documentNumber": {
            "type": "string",
            "description": "The document number, unformatted."
          },
          "personalNumber": {
            "type": "string",
            "description": "The national identifier printed on the document when it is a separate field from\nDocumentNumber — on a passport, the person's number rather than the booklet's. Null when\nthe document carries no separate one.",
            "nullable": true
          },
          "issuingState": {
            "type": "string",
            "description": "The state that issued the document (ISO 3166-1 alpha-3)."
          },
          "dateOfIssue": {
            "type": "string",
            "description": "When the document was issued. Null on records verified before the date was kept, and on documents\nthat do not print it.",
            "format": "date",
            "nullable": true
          },
          "documentExpiry": {
            "type": "string",
            "description": "When the document expires.",
            "format": "date"
          }
        }
      },
      "SharedImage": {
        "type": "object",
        "description": "One verified image a member shared with a company — the portrait (B+) or the capture of their\ndocument (D+) — as the shared-data read returns it.\n            \nThe bytes themselves rather than a link, for the reason the backoffice's media read gives: a signed URL\nleaves authorization behind, and whoever holds it reads the file until the signature lapses however the\nconsent changes afterwards. Every image a company sees is therefore a read the grant token allowed and the\naccess log recorded.",
        "additionalProperties": false,
        "required": [
          "contentType",
          "content"
        ],
        "properties": {
          "contentType": {
            "type": "string",
            "description": "The image's media type, e.g. image/jpeg."
          },
          "content": {
            "type": "string",
            "description": "The image, base64-encoded."
          }
        }
      },
      "GetSharedRecordRequest": {
        "type": "object",
        "description": "A company's read of what a member shared with it, the one door through which shared data leaves.\nGET /biometric/records/shared?include=biographic,document, with the grant token in the\nX-Grant-Token header.\n            \nNo id of a person anywhere, on purpose. Whose record and which company are both in the grant token Coreo\nsigned when it checked the grant (ADR-0027), so there is nothing here a caller could change to read\nsomebody else. The grant token rides in a header rather than the query string so it never lands in an\naccess log.\n            \nOne route for every resource rather than one per resource, so a company has a single place to read a\nmember's data from and a new resource is a new section of the answer, not a new endpoint. What is read\nis still asked for explicitly: each name in Include is one entry in the access log, so a\nconsole opening one card reads — and records — that card alone.",
        "additionalProperties": false
      },
      "VerifyWebhookSubscriptionResponse": {
        "type": "object",
        "description": "The outcome of an endpoint-verification handshake. An endpoint that fails the handshake is not\na caller error — the request was well formed and the platform did its part — so this answers 200 with\nverified false and the reason, rather than an error status that would say the caller did\nsomething wrong.",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "description": "The subscription id.",
            "format": "guid"
          },
          "verified": {
            "type": "boolean",
            "description": "Whether the endpoint passed the challenge/echo handshake."
          },
          "status": {
            "type": "string",
            "description": "Lifecycle state after the attempt (Active once verified, otherwise unchanged)."
          },
          "verifiedAt": {
            "type": "string",
            "description": "When the endpoint was verified, if it has been.",
            "format": "date-time",
            "nullable": true
          },
          "responseStatusCode": {
            "type": "integer",
            "description": "The HTTP status the endpoint answered with, when it answered at all.",
            "format": "int32",
            "nullable": true
          },
          "error": {
            "type": "string",
            "description": "Why the handshake failed — transport error, non-2xx, or a missing/incorrect echo; null on success.",
            "nullable": true
          }
        }
      },
      "VerifyWebhookSubscriptionRequest": {
        "type": "object",
        "description": "Supervisor-facing request to run the endpoint-verification handshake for a webhook subscription: the\nplatform POSTs a signed endpoint.verification ping carrying a one-time challenge, and the\nsubscription goes Pending → Active only if the endpoint answers 2xx echoing that challenge.",
        "additionalProperties": false
      },
      "ResumeWebhookSubscriptionRequest": {
        "type": "object",
        "description": "Supervisor-facing request to resume a paused webhook subscription.",
        "additionalProperties": false
      },
      "PauseWebhookSubscriptionRequest": {
        "type": "object",
        "description": "Supervisor-facing request to pause deliveries for a webhook subscription.",
        "additionalProperties": false
      },
      "ListWebhookSubscriptionsResponse": {
        "type": "object",
        "description": "The company's webhook subscriptions (newest first). Never includes the HMAC secret.",
        "additionalProperties": false,
        "properties": {
          "items": {
            "type": "array",
            "description": "The subscriptions, newest first.",
            "items": {
              "$ref": "#/components/schemas/WebhookSubscriptionListItem"
            }
          }
        }
      },
      "WebhookSubscriptionListItem": {
        "type": "object",
        "description": "A single webhook subscription in a listing — config only, no secret.",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "description": "The subscription id.",
            "format": "guid"
          },
          "label": {
            "type": "string",
            "description": "The human label."
          },
          "endpointUrl": {
            "type": "string",
            "description": "The delivery URL."
          },
          "eventTypes": {
            "type": "array",
            "description": "The subscribed event types.",
            "items": {
              "type": "string"
            }
          },
          "payloadVersion": {
            "type": "string",
            "description": "The contract version."
          },
          "status": {
            "type": "string",
            "description": "Lifecycle state (Pending / Active / Paused / Deleted)."
          },
          "verifiedAt": {
            "type": "string",
            "description": "When the endpoint was verified, if it has been.",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "description": "When the subscription was created.",
            "format": "date-time"
          }
        }
      },
      "ListWebhookSubscriptionsRequest": {
        "type": "object",
        "description": "Supervisor-facing request to list the company's webhook subscriptions (secret never returned).",
        "additionalProperties": false
      },
      "ListWebhookEventsResponse": {
        "type": "object",
        "description": "The webhook event types a company may subscribe to, with a short description of each.",
        "additionalProperties": false,
        "properties": {
          "items": {
            "type": "array",
            "description": "The available event types.",
            "items": {
              "$ref": "#/components/schemas/WebhookEventDescriptor"
            }
          }
        }
      },
      "WebhookEventDescriptor": {
        "type": "object",
        "description": "A subscribable webhook event type and what it means.",
        "additionalProperties": false,
        "properties": {
          "type": {
            "type": "string",
            "description": "The event type wire identifier (e.g. petition.approved)."
          },
          "description": {
            "type": "string",
            "description": "A short human-readable description."
          }
        }
      },
      "ListWebhookEventsRequest": {
        "type": "object",
        "description": "Request to discover the webhook event types a company may subscribe to.",
        "additionalProperties": false
      },
      "GetWebhookSubscriptionResponse": {
        "type": "object",
        "description": "One of the company's webhook subscriptions. Never includes the HMAC secret.",
        "additionalProperties": false,
        "required": [
          "subscription"
        ],
        "properties": {
          "subscription": {
            "description": "The subscription, in the same shape the listing returns it.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/WebhookSubscriptionListItem"
              }
            ]
          }
        }
      },
      "GetWebhookSubscriptionRequest": {
        "type": "object",
        "description": "Supervisor-facing request to read one of the company's webhook subscriptions by id (secret never\nreturned) — how an integrator asks whether a subscription is still active after auto-pause, instead of\nlisting every subscription to find one. Another company's subscription answers 404, the same as a\nmissing or deleted one.",
        "additionalProperties": false
      },
      "DeleteWebhookSubscriptionRequest": {
        "type": "object",
        "description": "Supervisor-facing request to delete (soft-delete) a webhook subscription.",
        "additionalProperties": false
      },
      "CreateWebhookSubscriptionResponse": {
        "type": "object",
        "description": "The result of registering a webhook subscription. HmacSecret is returned once,\nat creation, and never again — the client signs/verifies deliveries with it. The subscription starts\nPending until its endpoint is verified.",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "description": "The new subscription id.",
            "format": "guid"
          },
          "label": {
            "type": "string",
            "description": "The human label."
          },
          "endpointUrl": {
            "type": "string",
            "description": "The delivery URL."
          },
          "eventTypes": {
            "type": "array",
            "description": "The subscribed event types.",
            "items": {
              "type": "string"
            }
          },
          "payloadVersion": {
            "type": "string",
            "description": "The contract version."
          },
          "hmacSecret": {
            "type": "string",
            "description": "The HMAC signing secret — shown once, never retrievable again."
          },
          "status": {
            "type": "string",
            "description": "Lifecycle state (starts Pending)."
          },
          "createdAt": {
            "type": "string",
            "description": "When the subscription was created.",
            "format": "date-time"
          }
        }
      },
      "CreateWebhookSubscriptionRequest": {
        "type": "object",
        "description": "Supervisor-facing request to register a webhook subscription. The subscription starts\nPending; its HMAC signing secret is returned once in the response and never again.",
        "additionalProperties": false,
        "required": [
          "label",
          "endpointUrl",
          "eventTypes"
        ],
        "properties": {
          "label": {
            "type": "string",
            "description": "A human label to distinguish among several subscriptions."
          },
          "endpointUrl": {
            "type": "string",
            "description": "The HTTPS delivery URL."
          },
          "eventTypes": {
            "type": "array",
            "description": "The event types to subscribe to (must be within the subscribable event catalogue).",
            "items": {
              "type": "string"
            }
          },
          "payloadVersion": {
            "type": "string",
            "description": "The contract version to integrate against (default v1)."
          },
          "headers": {
            "type": "object",
            "description": "Optional static HTTP headers added on every delivery.",
            "nullable": true,
            "additionalProperties": {
              "type": "string"
            }
          },
          "metadata": {
            "type": "object",
            "description": "Optional opaque client metadata echoed back on every delivery.",
            "nullable": true,
            "additionalProperties": {
              "type": "string"
            }
          }
        }
      },
      "ListPetitionTemplatesResponse": {
        "type": "object",
        "description": "The company's active petition templates.",
        "additionalProperties": false,
        "properties": {
          "items": {
            "type": "array",
            "description": "The templates, newest first.",
            "items": {
              "$ref": "#/components/schemas/PetitionTemplateListItem"
            }
          }
        }
      },
      "PetitionTemplateListItem": {
        "type": "object",
        "description": "A single petition template in a listing.",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "description": "The template id.",
            "format": "guid"
          },
          "name": {
            "type": "string",
            "description": "The template name."
          },
          "assuranceRequired": {
            "description": "The required assurance level, or null when approval demands no proof.",
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/AssuranceLevel"
              }
            ]
          },
          "expiresInSeconds": {
            "type": "integer",
            "description": "The expiry window in seconds.",
            "format": "int32"
          },
          "bundle": {
            "type": "string",
            "description": "The bundle name the template was authored with, when one was used; otherwise null.",
            "nullable": true
          },
          "requestedCategories": {
            "type": "array",
            "description": "Every data-category code the shape asks for. Always populated, whether the author named a bundle\nor listed codes: the server expands a bundle once, at creation, and stores the result. Empty only\nfor a documents-only template.",
            "items": {
              "type": "string"
            }
          },
          "message": {
            "type": "string",
            "description": "The message snapshotted into a created petition."
          },
          "documents": {
            "type": "array",
            "description": "The document obligations the shape carries.",
            "items": {
              "$ref": "#/components/schemas/TemplateDocumentView"
            }
          }
        }
      },
      "AssuranceLevel": {
        "type": "integer",
        "description": "Cross-context assurance scale — the single, shared source of truth for \"how strong\" an\nauthentication is. A relying operation states a minimum level and a caller presents one; the two are\ncompared by Coreo.Domain.Access.AssuranceDemand.IsSatisfied (or, for an endpoint gate, by the\nchassis authorization handler). Shared so every context speaks assurance by value without referencing\neach other.\n            \nThe member names are the level, not the product word for it. The friendly names people\nread live in the clients that render them; putting them here meant a rename of a\nproduct word implied a token vocabulary migration, and it leaked onto the wire through the petition\nchecklist. The number is what Keycloak orders step-up by, so it is the half that cannot be renamed\nwithout changing meaning.\n            \nThere is no level for \"nothing demanded\". An operation that requires no proof states\nnull — see Petition.AssuranceRequired. A zero member would have to be\nexcluded by hand everywhere the scale is treated as a ladder, which is what the retired Ack\nmember cost: six guard sites whose only job was to stop it behaving like a level.",
        "x-enumNames": [
          "Loa1",
          "Loa2",
          "Loa3"
        ],
        "enum": [
          1,
          2,
          3
        ]
      },
      "TemplateDocumentView": {
        "type": "object",
        "description": "One document obligation on a stored template, as the reads report it.\nAn obligation and never a file. The template says a contract must be signed; which bytes answer\nthat is decided per petition, when the agent attaches them. Reads therefore carry no locator, no name\nand no size — there is nothing to name until a petition exists.",
        "additionalProperties": false,
        "properties": {
          "kind": {
            "type": "string",
            "description": "ToSign (the company attaches, the member signs) or Requested (the member supplies)."
          },
          "label": {
            "type": "string",
            "description": "The label shown to whoever has to act on the obligation."
          }
        }
      },
      "ListPetitionTemplatesRequest": {
        "type": "object",
        "description": "Request to list the company's active petition templates, the shapes its petitions are built from.\nCompany scope comes from the token (agent or API key).",
        "additionalProperties": false
      },
      "PetitionTemplateResponse": {
        "type": "object",
        "description": "A petition template's shape — everything a company needs to build a matching petition (assurance,\nexpiry, requested categories or preset segment, and the message).",
        "additionalProperties": false,
        "properties": {
          "id": {
            "type": "string",
            "description": "The template id.",
            "format": "guid"
          },
          "name": {
            "type": "string",
            "description": "The template name."
          },
          "assuranceRequired": {
            "description": "The required assurance level, or null when approval demands no proof.",
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/AssuranceLevel"
              }
            ]
          },
          "expiresInSeconds": {
            "type": "integer",
            "description": "The expiry window in seconds a created petition would use.",
            "format": "int32"
          },
          "bundle": {
            "type": "string",
            "description": "The bundle name the template was authored with, when one was used; otherwise null.",
            "nullable": true
          },
          "requestedCategories": {
            "type": "array",
            "description": "Every data-category code the shape asks for. Always populated, whether the author named a bundle\nor listed codes: the server expands a bundle once, at creation, and stores the result. Empty only\nfor a documents-only template.",
            "items": {
              "type": "string"
            }
          },
          "message": {
            "type": "string",
            "description": "The message snapshotted into a created petition."
          },
          "documents": {
            "type": "array",
            "description": "The document obligations the shape carries.",
            "items": {
              "$ref": "#/components/schemas/TemplateDocumentView"
            }
          }
        }
      },
      "GetPetitionTemplateRequest": {
        "type": "object",
        "description": "Request to inspect a single petition template by id.",
        "additionalProperties": false
      },
      "UploadProviderDocumentResponse": {
        "type": "object",
        "description": "Response returned after a provider attaches a to-sign document's file.",
        "additionalProperties": false,
        "properties": {
          "itemId": {
            "type": "string",
            "description": "The workspace item now holding the file.",
            "format": "guid"
          },
          "version": {
            "type": "integer",
            "description": "The item version after the upload (incremented on each replace).",
            "format": "int32"
          },
          "sizeBytes": {
            "type": "integer",
            "description": "The stored file size in bytes.",
            "format": "int64"
          }
        }
      },
      "UploadProviderDocumentRequest": {
        "type": "object",
        "description": "Company-facing request to attach the file for a ToSign document in a petition's file space —\nthe provider's half of the document flow, the counterpart to the user-facing upload of a\nRequested document.\nA separate endpoint rather than a shared one: the two uploads differ in who may call them, which slot\nkind they may fill, and which direction the file travels. Folding them together would put both\nauthorization paths in one handler and make the narrower one easy to widen by accident.",
        "additionalProperties": false,
        "required": [
          "contentBase64",
          "contentType"
        ],
        "properties": {
          "contentBase64": {
            "type": "string",
            "description": "The file content, Base64-encoded."
          },
          "contentType": {
            "type": "string",
            "description": "The file MIME type (e.g. application/pdf)."
          }
        }
      },
      "ListPetitionsResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PagedResponse"
          },
          {
            "type": "object",
            "description": "A page of the company's petitions.",
            "additionalProperties": false,
            "properties": {
              "items": {
                "type": "array",
                "description": "The page, newest first.",
                "items": {
                  "$ref": "#/components/schemas/PetitionListItem"
                }
              }
            }
          }
        ]
      },
      "PetitionListItem": {
        "type": "object",
        "description": "One petition in the company's list.\nNot an IResponse, following CompanyListItem: a row is not a reply, and putting a\nstatusCode on every element says nothing about the row while inviting a client to read it as\nthough it did.",
        "additionalProperties": false,
        "required": [
          "id",
          "targetProfileId",
          "status",
          "signatureRequired",
          "documentCount",
          "requestedByType",
          "createdAt",
          "expiresAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The petition id.",
            "format": "guid"
          },
          "targetProfileId": {
            "type": "string",
            "description": "The targeted profile.",
            "format": "guid"
          },
          "displayName": {
            "type": "string",
            "description": "The target's display name, or null when the profile no longer resolves. Null is a real state the\nlist must render — the petition outlives the profile — so it is reported rather than blanked.",
            "nullable": true
          },
          "username": {
            "type": "string",
            "description": "The target's platform username (prefix, issuing state, document number), when it resolves.",
            "nullable": true
          },
          "avatarUrl": {
            "type": "string",
            "description": "The target's avatar thumbnail, when they have one.",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "The lifecycle state as a reader should be told it — Timeout from the instant the deadline\npasses, whether or not the expiry sweep has written that to the row yet."
          },
          "assuranceRequired": {
            "description": "The assurance the target must present to approve.",
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/AssuranceLevel"
              }
            ]
          },
          "requestedCategories": {
            "type": "array",
            "description": "The data-category codes asked for. Empty for a documents-only petition.",
            "items": {
              "type": "string"
            }
          },
          "signatureRequired": {
            "type": "boolean",
            "description": "Whether any obligation needs the target's signature — what the list's \"firma\" chip reads."
          },
          "documentCount": {
            "type": "integer",
            "description": "How many document obligations the petition carries, signature and upload alike.",
            "format": "int32"
          },
          "templateId": {
            "type": "string",
            "description": "The template this petition's shape was snapshotted from, or null when it was shaped inline.",
            "format": "guid",
            "nullable": true
          },
          "requestedByType": {
            "type": "string",
            "description": "Whether an agent or an API key asked: Agent or ApiKey."
          },
          "createdAt": {
            "type": "string",
            "description": "When the petition was created.",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "description": "When it expires — what a countdown on an open row reads.",
            "format": "date-time"
          },
          "completedAt": {
            "type": "string",
            "description": "When it closed, or null while open. A lapsed petition reports its own deadline rather than null or\n\"now\", so the row does not claim it closed the moment somebody looked.",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "PagedResponse": {
        "type": "object",
        "description": "What every paged list endpoint answers with besides its rows (ADR-0033 D4). The derived response declares\nits own typed Items.\nNot generic: the TypeScript generator skips generic type definitions, so a PagedResponse<TItem>\nwould never reach the clients and every response deriving from it would reference a base that does not\nexist there. Rule L2 asserts the Items half instead.",
        "x-abstract": true,
        "additionalProperties": false,
        "required": [
          "total",
          "page",
          "pageSize"
        ],
        "properties": {
          "total": {
            "type": "integer",
            "description": "Rows matching scope, filters and search, across all pages — what the paginator counts.",
            "format": "int32"
          },
          "page": {
            "type": "integer",
            "description": "The page actually served, 1-based.",
            "format": "int32"
          },
          "pageSize": {
            "type": "integer",
            "description": "The page size actually applied, after clamping — so a client never pages from a size it did not get.",
            "format": "int32"
          },
          "truncated": {
            "type": "boolean",
            "description": "Whether a source stopped short of everything that matched — a roster read from the identity provider,\nor a person search across modules that hit its cap. Null on a list that cannot be capped.",
            "nullable": true
          }
        }
      },
      "ListPetitionsRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PagedListRequest"
          },
          {
            "type": "object",
            "description": "Lists the authenticated company's petitions, newest first. Gated on identification:read.\nStrictly company-scoped: the company comes from the caller's tenancy and there is no unnarrowed view,\nunlike the company and agent rosters. A petition names a person and what was asked of them, so no\ncaller reads another company's — and nothing in the platform yet needs a cross-tenant one.",
            "additionalProperties": false
          }
        ]
      },
      "PagedListRequest": {
        "type": "object",
        "description": "What every paged list endpoint takes (ADR-0033 D1): one free-text Search and a window. A list's\nown filters are typed properties on the derived request; they match exactly and combine with the search.\nA base record rather than an interface so the defaults and these docs exist once — six requests each held\ntheir own copy before, with two different default page sizes. The derived request still implements\nIRequest itself, since its route, verb and group are its own.",
        "x-abstract": true,
        "additionalProperties": false
      },
      "ProviderPetitionResponse": {
        "type": "object",
        "description": "One petition as the company that raised it sees it: what was asked, who asked, and how it turned out.\nEverything here is something the company already knows or is entitled to — its own ask, its own\nrequester, and the outcome. Deliberately absent is the resolution checklist the member's read carries\n(AssuranceSatisfied, MissingCategories, Actions, CanApprove): that is the\ncapability gap, and ADR-0005 §7 keeps it from the requester.",
        "additionalProperties": false,
        "required": [
          "id",
          "status",
          "requestedByType",
          "target",
          "createdAt",
          "expiresAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The petition id.",
            "format": "guid"
          },
          "status": {
            "type": "string",
            "description": "The lifecycle state as a reader should be told it — Timeout from the instant the deadline\npasses, whether or not the expiry sweep has written that to the row yet."
          },
          "assuranceRequired": {
            "description": "The assurance the target had to present to approve.",
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/AssuranceLevel"
              }
            ]
          },
          "message": {
            "type": "string",
            "description": "The message shown to the target, snapshotted at creation.",
            "nullable": true
          },
          "templateId": {
            "type": "string",
            "description": "The template the shape was snapshotted from, or null when it was shaped inline.",
            "format": "guid",
            "nullable": true
          },
          "templateName": {
            "type": "string",
            "description": "That template's name, or null when there was none — or when the template has since been deleted.\nThe petition keeps its shape either way: a template is snapshotted on use, never read back.",
            "nullable": true
          },
          "requestedByType": {
            "type": "string",
            "description": "Who asked: Agent or ApiKey."
          },
          "requestedBy": {
            "description": "The agent who raised it, when a person did and their profile still resolves. Null for an\nAPI-key petition — a machine principal has no name to show, and inventing one would misattribute\nthe ask.",
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/PetitionPartyItem"
              }
            ]
          },
          "requestedByApiKeyId": {
            "type": "string",
            "description": "The company API key that raised it, for an API-key petition; null for an agent's. An id, not a name:\nthe name belongs to Tenant, and the console resolves it there — only for a viewer allowed to read the\ncompany's keys — instead of this read crossing into another module on every open.",
            "format": "guid",
            "nullable": true
          },
          "target": {
            "description": "The person it was addressed to.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/PetitionPartyItem"
              }
            ]
          },
          "categories": {
            "type": "array",
            "description": "The data categories asked for, in the order the petition recorded them.",
            "items": {
              "$ref": "#/components/schemas/PetitionCategoryItem"
            }
          },
          "requirements": {
            "type": "array",
            "description": "The document obligations the petition carries.",
            "items": {
              "$ref": "#/components/schemas/PetitionRequirementItem"
            }
          },
          "sharedData": {
            "description": "What the member shared by approving, and the grant token to read it with. Null unless the petition was\napproved and at least one of the grants it created is still active.",
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/PetitionSharedData"
              }
            ]
          },
          "createdAt": {
            "type": "string",
            "description": "When the petition was created.",
            "format": "date-time"
          },
          "expiresAt": {
            "type": "string",
            "description": "When it expires.",
            "format": "date-time"
          },
          "completedAt": {
            "type": "string",
            "description": "When it closed, or null while open. A lapsed petition reports its own deadline rather than null,\nso the record does not claim it closed the moment somebody looked.",
            "format": "date-time",
            "nullable": true
          },
          "rejectReason": {
            "type": "string",
            "description": "Why the member declined, as they chose it from the reasons the app offers — or null when the\npetition was not rejected, or was rejected without one. The member picks it in the reject sheet to\ntell the company, so the company is who reads it.",
            "nullable": true
          }
        }
      },
      "PetitionPartyItem": {
        "type": "object",
        "description": "A person on one side of a petition — the agent who asked, or the member who was asked.",
        "additionalProperties": false,
        "properties": {
          "profileId": {
            "type": "string",
            "description": "The profile id, when the party has one.",
            "format": "guid",
            "nullable": true
          },
          "displayName": {
            "type": "string",
            "description": "The display name, or null when the profile no longer resolves.",
            "nullable": true
          },
          "username": {
            "type": "string",
            "description": "The platform username (prefix, issuing state, document number), when it resolves.",
            "nullable": true
          },
          "avatarUrl": {
            "type": "string",
            "description": "The avatar thumbnail, when there is one.",
            "nullable": true
          }
        }
      },
      "PetitionCategoryItem": {
        "type": "object",
        "description": "One data category the petition asked for.\nAn object holding a single field on purpose, so anything later known per category can be added\nwithout a breaking change. Whether a category was granted and is still active is not here: it is in the\nresponse's SharedData.Grants, next to the grant token that reads the values, because the grant and\nthe read go together and a petition that was not approved has neither.",
        "additionalProperties": false,
        "required": [
          "code"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "The DataCategory code, e.g. B, D+, R++."
          }
        }
      },
      "PetitionRequirementItem": {
        "type": "object",
        "description": "One document obligation, as the company that asked for it sees it.\nThe kind and the label only. Whether the member has satisfied it yet is withheld pending a decision\non how far ADR-0005 §7's opacity reaches — an open petition's per-obligation progress is arguably the\nsender's business and arguably the member's, and withholding it is the choice that stays additive.\nThe petition's own status already reports the outcome.",
        "additionalProperties": false,
        "required": [
          "id",
          "kind",
          "label"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The obligation id — the handle the provider-upload endpoint takes.",
            "format": "guid"
          },
          "kind": {
            "type": "string",
            "description": "ToSign (the company attaches, the member signs) or Requested."
          },
          "label": {
            "type": "string",
            "description": "The label shown to whoever has to act on it."
          }
        }
      },
      "PetitionSharedData": {
        "type": "object",
        "description": "What a company may read of the data a member shared by approving a petition, and the grant token to read it\nwith (ADR-0027).\n            \nThe values themselves are not here. Coreo holds the consent and Biometric holds the data, and neither\ncalls the other: Coreo decides, signs that decision into GrantToken, and the caller presents\nit to GET biometric/records/shared, including only the resources it actually wants to see. That\nkeeps the read lazy — a console fetches a card's values only when the card is opened — and puts the\naccess record where the data actually leaves the platform rather than where it merely could have.",
        "additionalProperties": false,
        "properties": {
          "grants": {
            "type": "array",
            "description": "The data-category codes this petition's approval granted that are still active — not revoked, not\nsuperseded by a later petition for the same data. A requested code missing here was never granted\nor has since been withdrawn.",
            "items": {
              "type": "string"
            }
          },
          "resources": {
            "type": "array",
            "description": "The resources GrantToken opens, as named in SharedRecordResources: the fields\n(biographic, document) and the images (portrait, capture). Empty when no\ngrant has anything behind it to read.",
            "items": {
              "type": "string"
            }
          },
          "grantToken": {
            "type": "string",
            "description": "The signed grant token to send as the X-Grant-Token header when reading a resource. Opaque; null\nwhen Resources is empty. Redeemable only by the company the petition belongs to.",
            "nullable": true
          },
          "grantTokenExpiresAt": {
            "type": "string",
            "description": "When GrantToken stops being accepted. A read after this answers 403 with\nGRANT_TOKEN_EXPIRED; reading the petition again returns a fresh grant token while the grants\nhold.",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "GetProviderPetitionRequest": {
        "type": "object",
        "description": "Reads one petition as the company that raised it sees it. Gated on identification:read\nand the caller's tenancy.\nA separate route from petitions/{id} rather than that endpoint widened, because the two answer\ndifferent callers under opposite rules. The member's read returns the resolution checklist — the\nassurance step-up still owed, the categories not yet held, whether approval is possible — and\nADR-0005 §7 forbids the\nrequester ever seeing that gap. One response type serving both audiences is precisely how it would\nleak.\nprovider is the domain's own word for the company side (ProviderName,\nUploadProviderDocument, ItemOrigin.Provider) and not a caller identity: an agent and an\nAPI key read the same representation.",
        "additionalProperties": false
      },
      "ProviderDocumentResponse": {
        "type": "object",
        "description": "One document obligation as the company that raised the petition sees it: the file it holds, and the\nsignature proof once the member has signed.\n            \nDeliberately not GetDocumentResponse with extra fields. The member's read is about\nacting on the obligation; this one is about holding the instrument afterwards, so it carries the\nevidence — when it was signed, which version and hash was signed, and the stroke itself — and none of\nthe member-facing framing.",
        "additionalProperties": false,
        "properties": {
          "requirementId": {
            "type": "string",
            "description": "The obligation this describes.",
            "format": "guid"
          },
          "label": {
            "type": "string",
            "description": "The human label, as the template worded it."
          },
          "kind": {
            "type": "string",
            "description": "The obligation kind: Requested (the member provides) or ToSign (the member signs)."
          },
          "itemId": {
            "type": "string",
            "description": "The workspace item answering it, or null while nothing does.",
            "format": "guid",
            "nullable": true
          },
          "contentType": {
            "type": "string",
            "description": "The file's MIME type, when a file answers this obligation.",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "A short-lived URL for the instrument, or null when there is nothing to serve — nothing provided\nyet, or bytes reclaimed past retention. Null is a normal answer, not an error.",
            "nullable": true
          },
          "sizeBytes": {
            "type": "integer",
            "description": "The stored file size in bytes, when known.",
            "format": "int64",
            "nullable": true
          },
          "version": {
            "type": "integer",
            "description": "The current item version. A signed item never moves again, so this is the version signed.",
            "format": "int32"
          },
          "hash": {
            "type": "string",
            "description": "SHA-256 of the stored bytes — what the proof attests to, so the file can be checked against it.",
            "nullable": true
          },
          "isSigned": {
            "type": "boolean",
            "description": "Whether the member has signed."
          },
          "signedAt": {
            "type": "string",
            "description": "When the member signed; null until they do.",
            "format": "date-time",
            "nullable": true
          },
          "accepted": {
            "type": "boolean",
            "description": "Whether the member affirmatively accepted the document. Only meaningful once\nIsSigned is true; null before that.",
            "nullable": true
          },
          "signatureUrl": {
            "type": "string",
            "description": "A short-lived URL for the hand-drawn signature image, when the member drew one and it has not\nbeen reclaimed. Null means no stroke was captured — acceptance without a drawing is still a\nsignature — or that its retention has lapsed.",
            "nullable": true
          },
          "signatureContentType": {
            "type": "string",
            "description": "The signature image's MIME type, when one is stored.",
            "nullable": true
          },
          "deviceSignature": {
            "description": "The member's device signature (ADR-0024). That the payload was signed by the key it carries is\nverifiable without the platform; that the key is the member's is the platform's record (D12). Null for\na document not yet signed, and for one signed before device signing existed — that proof rests on the\nrecord alone.",
            "nullable": true,
            "oneOf": [
              {
                "$ref": "#/components/schemas/DeviceSignatureView"
              }
            ]
          },
          "purgedAt": {
            "type": "string",
            "description": "When the bytes were reclaimed past retention; null while they are still there.",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "DeviceSignatureView": {
        "type": "object",
        "description": "The member's device signature on a signed document, as the company that holds the instrument receives\nit (ADR-0024). Enough to verify, without asking the platform, that the payload was signed by\nPublicKey: verify Signature with it (ECDSA P-256, SHA-256, DER) over the\nUTF-8 bytes of Payload, and check that the payload's document-sha256 line matches\nthe file.\nNot enough on its own to prove the key is the member's. That binding is the platform's record of the\nsession the key was registered under, and the key travels in the same record as the signature, so a party\nable to rewrite both could substitute a key and a signature together (ADR-0024, D12).",
        "additionalProperties": false,
        "properties": {
          "scheme": {
            "type": "string",
            "description": "The payload scheme, e.g. twarz-doc-sign/v1."
          },
          "payload": {
            "type": "string",
            "description": "The exact text that was signed."
          },
          "signature": {
            "type": "string",
            "description": "The signature, Base64 of its DER encoding."
          },
          "keyId": {
            "type": "string",
            "description": "Lower-case hex SHA-256 of the public key's SPKI: a stable fingerprint for the key."
          },
          "publicKey": {
            "type": "string",
            "description": "The verifying public key, Base64 of its DER SubjectPublicKeyInfo."
          }
        }
      },
      "GetProviderDocumentRequest": {
        "type": "object",
        "description": "The requester's read of one document obligation: the instrument it holds and, once the member has\nsigned, the proof of that signature.\n            \nThe counterpart to GetDocumentRequest rather than a widening of it, the same split the\npetition read already makes. That one loads through the member's ownership and answers the person\nwhose file it is; this one is tenancy-scoped and answers the company that asked for the signature —\nwhich, until this existed, could not retrieve the signed instrument at all. For a signature workflow\nthat is the deliverable.",
        "additionalProperties": false
      },
      "CreatePetitionResponse": {
        "type": "object",
        "description": "Response returned when a petition is created.",
        "additionalProperties": false,
        "properties": {
          "petitionId": {
            "type": "string",
            "description": "The new petition id.",
            "format": "guid"
          },
          "status": {
            "type": "string",
            "description": "The petition's lifecycle status."
          },
          "expiresAt": {
            "type": "string",
            "description": "When the petition expires.",
            "format": "date-time"
          },
          "missingCategories": {
            "type": "array",
            "description": "The requested data-category codes the person does not hold today, in requested order — empty when\nthey hold every one.\n            \nThe petition is created and delivered either way: it is a warning, not a refusal. It exists because\nsome data can only be supplied by a proof the person has not made — the document's chip read, for a\nprofile enrolled without NFC — and until they make it they cannot approve. Without this the sender\nlearned it only when the petition timed out. What they hold can still change while the petition is\nopen, so this describes the moment of sending, not the outcome.",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "CreatePetitionRequest": {
        "type": "object",
        "description": "Company-facing request to create a Petition targeting a user from one of the company's\ntemplates. Issued by an authenticated Agent or API key; the company scope is taken from the token,\nnever from the body.\nA member this request does not declare is refused rather than ignored. The shape fields\n(assuranceRequired, requestedCategories, expiresInSeconds) used to be accepted\nhere; a caller still sending them must learn that the petition does not carry them, not believe it\nasked for something the template never named.",
        "additionalProperties": false,
        "required": [
          "targetUsername",
          "templateId",
          "providerName"
        ],
        "properties": {
          "targetUsername": {
            "type": "string",
            "description": "The target user's platform username (twid.arg.12345678)."
          },
          "templateId": {
            "type": "string",
            "description": "The company template the petition is built from. Required: the server snapshots the assurance,\nrequested categories, expiry window, message and documents from it, and records it as the\npetition's provenance.\nThere is no other way to shape a petition. A template is where a company defines what it asks for,\non the levels the platform offers, and a petition shaped per request could ask for a combination\nno level defines — which the console then has no honest way to show. ADR-0004 §2 already put the\nshape in the template; this makes it the only source.",
            "format": "guid"
          },
          "providerName": {
            "type": "string",
            "description": "The provider display name shown to the user (anti-phishing). Required: a template carries no\nprovider name, and this is the string the user reads to decide the ask is genuine — it\nmust never be defaulted."
          },
          "message": {
            "type": "string",
            "description": "An optional human-readable message describing what is being requested. Overrides the template's\nmessage when both are present.",
            "nullable": true
          },
          "documents": {
            "type": "array",
            "description": "The files the agent supplies for the template's ToSign obligations.\nCarried here rather than attached afterwards, because a petition is notified the moment it is\ncreated: the delivery event is scraped off the aggregate inside this command's transaction, so a\nfile that arrives in a second call arrives after the member has already been told to sign\nsomething that is not there yet. Every to-sign obligation the template declares must be answered\nhere, or nothing is created.",
            "nullable": true,
            "items": {
              "$ref": "#/components/schemas/PetitionDocumentInput"
            }
          }
        }
      },
      "PetitionDocumentInput": {
        "type": "object",
        "description": "One file the agent supplies for a document obligation the template declares.\nAddressed by position, which is exact rather than convenient: a template's presets are an ordered\nlist, Petition.Create appends one obligation per preset in that order, and the reads report\nthem in it. Matching on the label instead would look safer and be wrong — two presets may carry the\nsame label and need different files, and a label lookup would answer both with the first one.",
        "additionalProperties": false,
        "required": [
          "index",
          "contentBase64",
          "contentType"
        ],
        "properties": {
          "index": {
            "type": "integer",
            "description": "The obligation's zero-based position in the template's documents.",
            "format": "int32"
          },
          "contentBase64": {
            "type": "string",
            "description": "The file content, Base64-encoded (max ~10 MB decoded)."
          },
          "contentType": {
            "type": "string",
            "description": "The file MIME type — application/pdf, image/jpeg or image/png."
          }
        }
      },
      "DataCatalogResponse": {
        "type": "object",
        "description": "Response to GetDataCatalogRequest.",
        "additionalProperties": false,
        "properties": {
          "categories": {
            "type": "array",
            "description": "Every data-category code, in ladder order.",
            "items": {
              "$ref": "#/components/schemas/DataCatalogCategory"
            }
          },
          "bundles": {
            "type": "array",
            "description": "Every named bundle, shallowest first.",
            "items": {
              "$ref": "#/components/schemas/DataCatalogBundle"
            }
          }
        }
      },
      "DataCatalogCategory": {
        "type": "object",
        "description": "One data-category code as the catalog serves it.",
        "additionalProperties": false,
        "properties": {
          "code": {
            "type": "string",
            "description": "The code, e.g. D+. Stored by value on a grant."
          },
          "family": {
            "description": "The family the code belongs to, for grouping in a picker.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/DataFamily"
              }
            ]
          },
          "requestable": {
            "type": "boolean",
            "description": "Whether a template may ask for this code — true exactly when the verification that produces it is one\nthe platform can collect today. A defined-but-unrequestable code is one the platform can name and has\nno flow behind yet, so asking for it would create a petition the member cannot complete."
          }
        }
      },
      "DataFamily": {
        "type": "integer",
        "description": "The data family a DataCategory code belongs to (the code's leading letter).",
        "x-enumNames": [
          "Biographic",
          "Document",
          "Reach",
          "Sensitive"
        ],
        "enum": [
          0,
          1,
          2,
          3
        ]
      },
      "DataCatalogBundle": {
        "type": "object",
        "description": "One named bundle as the catalog serves it.",
        "additionalProperties": false,
        "properties": {
          "name": {
            "type": "string",
            "description": "The bundle name, e.g. verify. This is the stored value."
          },
          "codes": {
            "type": "array",
            "description": "The exact codes the bundle stands for.",
            "items": {
              "type": "string"
            }
          },
          "requestable": {
            "type": "boolean",
            "description": "Whether every code in the bundle is requestable, so the bundle as a whole can be asked for."
          }
        }
      },
      "GetDataCatalogRequest": {
        "type": "object",
        "description": "The data-access catalog a template author picks from: every data-category code with the family it\nbelongs to and whether it can be requested at all, plus every named bundle with the codes it stands\nfor.\n            \nServed rather than mirrored in each client. The codes and bundles are C# constant tables that TypeGen\ndoes not generate, so every console kept a hand-written copy — and they drifted: the web mirror's\nverify preset expanded to a different code set than the backend's, and a template could be\nauthored asking for a proof no member could supply. One served catalog is what makes \"requestable\" the\nsame fact on both sides.\nResolves to DataCatalogResponse.",
        "additionalProperties": false
      }
    },
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "description": "A company API key (tzk_…), created by a supervisor in the Web Agente console under \"Acceso API\".",
        "name": "X-Api-Key",
        "in": "header"
      }
    }
  }
}