{
  "openapi": "3.1.0",
  "info": {
    "title": "GSB e-Services partner API",
    "version": "1.0.0",
    "summary": "Service catalogue, permit verification, National Data Register reads, application status and webhooks for MDA and partner systems.",
    "description": "Authenticate with OAuth 2.0 client credentials: POST /oauth/token with your client ID and secret (HTTP Basic or form fields) to get a 15-minute bearer token, then call the API with Authorization: Bearer <token>. Each client has its own scopes, MDA and register scope, address allow-list, per-minute rate limit and daily quota; 429 answers carry Retry-After. Errors are RFC 7807 problem documents with a stable `code` and a `requestId`. Webhooks are signed: X-GSB-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256(secret, \"<t>.<raw body>\")>. Reject a message whose t is more than 5 minutes old; during a secret rotation two v1 values are sent and either may match. Deliveries are at least once: drop duplicates by the event id.",
    "contact": {
      "name": "GSB e-Services integration desk"
    }
  },
  "servers": [
    {
      "url": "/api/v1",
      "description": "This environment"
    }
  ],
  "tags": [
    {
      "name": "Authentication"
    },
    {
      "name": "Catalogue"
    },
    {
      "name": "Permits"
    },
    {
      "name": "Registers"
    },
    {
      "name": "Applications"
    },
    {
      "name": "Events"
    },
    {
      "name": "Audit"
    },
    {
      "name": "Geodata"
    },
    {
      "name": "Legacy consumers"
    }
  ],
  "paths": {
    "/oauth/token": {
      "post": {
        "operationId": "getToken",
        "tags": [
          "Authentication"
        ],
        "summary": "Get an access token (client credentials)",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "Unsupported grant type.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthError"
                }
              }
            }
          },
          "401": {
            "description": "Unknown client, wrong secret, or the client is not active.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthError"
                }
              }
            }
          },
          "403": {
            "description": "The address is not on the client's allow-list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthError"
                }
              }
            }
          },
          "429": {
            "description": "Too many failed attempts from this address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthError"
                }
              }
            }
          },
          "500": {
            "description": "Server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthError"
                }
              }
            }
          }
        }
      }
    },
    "/me": {
      "get": {
        "operationId": "getMe",
        "tags": [
          "Authentication"
        ],
        "summary": "The calling client, its scopes and limits",
        "security": [
          {
            "clientCredentials": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Me"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/services": {
      "get": {
        "operationId": "listServices",
        "tags": [
          "Catalogue"
        ],
        "summary": "Published services",
        "security": [
          {
            "clientCredentials": [
              "services:read"
            ]
          }
        ],
        "x-required-scope": "services:read",
        "parameters": [
          {
            "name": "mdaId",
            "in": "query",
            "required": false,
            "description": "Only this MDA's services",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-500 (100)",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Skip this many",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/services/{serviceId}": {
      "get": {
        "operationId": "getService",
        "tags": [
          "Catalogue"
        ],
        "summary": "One published service: passport, fees, required documents, steps",
        "security": [
          {
            "clientCredentials": [
              "services:read"
            ]
          }
        ],
        "x-required-scope": "services:read",
        "parameters": [
          {
            "name": "serviceId",
            "in": "path",
            "required": true,
            "description": "Service id",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/permits/verify/{code}": {
      "get": {
        "operationId": "verifyPermit",
        "tags": [
          "Permits"
        ],
        "summary": "Verify a permit, licence or certificate by its verification code or number",
        "security": [
          {
            "clientCredentials": [
              "permits:verify"
            ]
          }
        ],
        "x-required-scope": "permits:verify",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "description": "Verification code (QR) or permit number",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PermitVerification"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/verify/{documentNumber}": {
      "get": {
        "operationId": "verifyDocument",
        "tags": [
          "Permits"
        ],
        "summary": "Verify any document: this platform, a peer node, or a legacy ministry (issuer=<code>) - one answer",
        "description": "Answers 404 with reason not_found only when no source knows the document, 503 when a source could not be asked (never a false not_found), 409 with reason ambiguous when two nodes hold the number (give issuer), 429 (Retry-After) over the federated-check ceilings. On the national hub a document of a node is asked of that node (lib/federation/verifyLookup).",
        "security": [
          {
            "clientCredentials": [
              "permits:verify"
            ]
          }
        ],
        "x-required-scope": "permits:verify",
        "parameters": [
          {
            "name": "documentNumber",
            "in": "path",
            "required": true,
            "description": "Issued number or verification code",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "issuer",
            "in": "query",
            "required": false,
            "description": "The issuing ministry (short name) or node key: on the hub only that node is asked; a legacy ministry (VERIFY_HUB_ZAMPOINTS) is asked through its ZamPoint, e.g. ZEMA",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HubVerification"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/verify/documents": {
      "post": {
        "operationId": "verifyDocumentsBulk",
        "tags": [
          "Permits"
        ],
        "summary": "Bulk verification: codes and PDFs, each answered like the \"verify a document\" page of the portal",
        "description": "Codes need the permits:verify scope, PDFs documents:validate; an item the client may not check gets its own 403. PDFs are validated (seal, time-stamp, changes, issued record, lifecycle) and not kept.",
        "security": [
          {
            "clientCredentials": [
              "permits:verify"
            ]
          },
          {
            "clientCredentials": [
              "documents:validate"
            ]
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkVerifyResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "x-required-scope": "permits:verify | documents:validate",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkVerifyRequest"
              }
            }
          }
        }
      }
    },
    "/permits/{code}/uses": {
      "get": {
        "operationId": "listCertificateUses",
        "tags": [
          "Permits"
        ],
        "summary": "Whether a certificate can be used now, what is left of its quantity, and its uses",
        "description": "Only certificates of the ministries in the MDA scope of the client; anything else answers 404 like an unknown code.",
        "security": [
          {
            "clientCredentials": [
              "permits:consume"
            ]
          }
        ],
        "x-required-scope": "permits:consume",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "description": "Verification code or certificate number",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CertificateUses"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "post": {
        "operationId": "recordCertificateUse",
        "tags": [
          "Permits"
        ],
        "summary": "Record a use of a certificate (quantity drawn down, place, consignment)",
        "description": "Send Idempotency-Key. A certificate that is not in force, is used up, or has less left than asked is refused (409, nothing recorded). Every use is audited and shown to the holder.",
        "security": [
          {
            "clientCredentials": [
              "permits:consume"
            ]
          }
        ],
        "x-required-scope": "permits:consume",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "description": "Verification code or certificate number",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "8 to 80 letters, digits or . _ : - (a UUID is ideal); keep it when you retry.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CertificateUseRecorded"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CertificateUseRequest"
              }
            }
          }
        }
      }
    },
    "/registers": {
      "get": {
        "operationId": "listRegisters",
        "tags": [
          "Registers"
        ],
        "summary": "Registers this client may read",
        "security": [
          {
            "clientCredentials": [
              "registers:read"
            ]
          }
        ],
        "x-required-scope": "registers:read",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/registers/{code}/lookup": {
      "get": {
        "operationId": "lookupRegister",
        "tags": [
          "Registers"
        ],
        "summary": "Search a register by label or key prefix (at most 50)",
        "security": [
          {
            "clientCredentials": [
              "registers:read"
            ]
          }
        ],
        "x-required-scope": "registers:read",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "description": "Register code; write / as __",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "At least 2 characters",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-50 (20)",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterLookup"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/registers/{code}/entries/{key}": {
      "get": {
        "operationId": "getRegisterEntry",
        "tags": [
          "Registers"
        ],
        "summary": "One register entry by key",
        "description": "A key containing / (an NRC) cannot travel in the path through the gateway: use /registers/{code}/entries?key= instead.",
        "security": [
          {
            "clientCredentials": [
              "registers:read"
            ]
          }
        ],
        "x-required-scope": "registers:read",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "description": "Register code; write / as __",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "key",
            "in": "path",
            "required": true,
            "description": "Entry key",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterEntry"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/registers/{code}/entries": {
      "get": {
        "operationId": "getRegisterEntryByQuery",
        "tags": [
          "Registers"
        ],
        "summary": "One register entry by key, the key in the query string (keys with /, such as an NRC)",
        "security": [
          {
            "clientCredentials": [
              "registers:read"
            ]
          }
        ],
        "x-required-scope": "registers:read",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "description": "Register code; write / as __",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "key",
            "in": "query",
            "required": true,
            "description": "Entry key, URL-encoded",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterEntry"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/registers/{code}/changes": {
      "get": {
        "operationId": "getRegisterChanges",
        "tags": [
          "Registers"
        ],
        "summary": "What changed in a register since a cursor, deletions included (replay from the beginning with no cursor)",
        "description": "Oldest first. Each change carries the entry as it stands now, projected for the client like /entries; deleted and tombstoned entries come as state \"removed\". Keep nextCursor and send it next time; while more is true, ask again. The answer is signed (X-GSB-JWS, ES256, detached, over the body bytes; keys in /.well-known/jwks.json). Every call is audited.",
        "security": [
          {
            "clientCredentials": [
              "registers:read"
            ]
          }
        ],
        "x-required-scope": "registers:read",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "description": "Register code; write / as __",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "nextCursor of the previous answer; empty = from the beginning",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-1000 (100)",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterChanges"
                }
              }
            },
            "headers": {
              "X-GSB-JWS": {
                "description": "Detached compact JWS (ES256) over the body bytes.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/parties/{type}/{value}/links": {
      "get": {
        "operationId": "getPartyLinks",
        "tags": [
          "Registers"
        ],
        "summary": "The register entries an identifier appears in (companies directed, vehicles owned, parcels held), in the register scope of the client",
        "description": "type: nrc, tpin, passport, entity-number, plate, property-no, title-no, permit-no, zampass-id or any. An identifier containing / (an NRC) cannot travel in the path through the gateway: use /parties/{type}/links?value= instead. Every lookup is audited.",
        "security": [
          {
            "clientCredentials": [
              "registers:read"
            ]
          }
        ],
        "x-required-scope": "registers:read",
        "parameters": [
          {
            "name": "type",
            "in": "path",
            "required": true,
            "description": "Identifier type",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "value",
            "in": "path",
            "required": true,
            "description": "The identifier",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartyLinks"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/parties/{type}/links": {
      "get": {
        "operationId": "getPartyLinksByQuery",
        "tags": [
          "Registers"
        ],
        "summary": "The register entries an identifier appears in, the identifier in the query string (an NRC)",
        "security": [
          {
            "clientCredentials": [
              "registers:read"
            ]
          }
        ],
        "x-required-scope": "registers:read",
        "parameters": [
          {
            "name": "type",
            "in": "path",
            "required": true,
            "description": "Identifier type",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "value",
            "in": "query",
            "required": true,
            "description": "The identifier, URL-encoded",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PartyLinks"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/cases/{caseNumber}/status": {
      "get": {
        "operationId": "getCaseStatus",
        "tags": [
          "Applications"
        ],
        "summary": "Where an application stands (cases of the client's MDAs only)",
        "description": "No personal data is returned.",
        "security": [
          {
            "clientCredentials": [
              "cases:read"
            ]
          }
        ],
        "x-required-scope": "cases:read",
        "parameters": [
          {
            "name": "caseNumber",
            "in": "path",
            "required": true,
            "description": "The application number",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CaseStatus"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/events": {
      "get": {
        "operationId": "listEventTypes",
        "tags": [
          "Events"
        ],
        "summary": "The event catalogue",
        "security": [
          {
            "clientCredentials": [
              "events:subscribe"
            ]
          }
        ],
        "x-required-scope": "events:subscribe",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventCatalogue"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/webhooks": {
      "get": {
        "operationId": "listMySubscriptions",
        "tags": [
          "Events"
        ],
        "summary": "This client's webhook subscriptions (administrators create them)",
        "security": [
          {
            "clientCredentials": [
              "events:subscribe"
            ]
          }
        ],
        "x-required-scope": "events:subscribe",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/audit/events": {
      "get": {
        "operationId": "listAuditEvents",
        "tags": [
          "Audit"
        ],
        "summary": "Audit events about applications of the client's MDAs, oldest first, from a sequence number on",
        "description": "Replay: pass the last sequence you stored as `after`. Events carry identifiers, roles at the time and the marking - never names, addresses or before / after values. Applications whose marking may not be exposed to partner systems are left out.",
        "security": [
          {
            "clientCredentials": [
              "audit:read"
            ]
          }
        ],
        "x-required-scope": "audit:read",
        "parameters": [
          {
            "name": "after",
            "in": "query",
            "required": false,
            "description": "Only events with a higher sequence (0: from the start)",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-500 (100)",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditEventPage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/geo/feeds": {
      "get": {
        "operationId": "listGeoFeeds",
        "tags": [
          "Geodata"
        ],
        "summary": "The GeoJSON feeds this platform publishes",
        "security": [
          {
            "clientCredentials": [
              "geo:read"
            ]
          }
        ],
        "x-required-scope": "geo:read",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeoFeedList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/geo/feeds/{key}": {
      "get": {
        "operationId": "getGeoFeed",
        "tags": [
          "Geodata"
        ],
        "summary": "One feed as a GeoJSON FeatureCollection, paged",
        "description": "Answers application/geo+json with an ETag: poll with If-None-Match. Follow links[rel=next] for the next page.",
        "security": [
          {
            "clientCredentials": [
              "geo:read"
            ]
          }
        ],
        "x-required-scope": "geo:read",
        "parameters": [
          {
            "name": "key",
            "in": "path",
            "required": true,
            "description": "Feed key, e.g. forestry.licensed-areas",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1-2000 (1000)",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Skip this many",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "bbox",
            "in": "query",
            "required": false,
            "description": "minLon,minLat,maxLon,maxLat (WGS 84)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "updatedSince",
            "in": "query",
            "required": false,
            "description": "Only features changed since (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/geo+json": {
                "schema": {
                  "$ref": "#/components/schemas/GeoFeatureCollection"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/parties/associated-entities": {
      "post": {
        "operationId": "getAssociatedEntities",
        "tags": [
          "Legacy consumers"
        ],
        "summary": "Organisations a person (by NRC) represents",
        "description": "Replaces ZIGS GET /Corporate/GetAssociatedEntities?nrc= (ZamPass portal). Active, approved mandates only.",
        "security": [
          {
            "clientCredentials": [
              "parties:read"
            ]
          }
        ],
        "x-required-scope": "parties:read",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssociatedEntities"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NrcQuery"
              }
            }
          }
        }
      }
    },
    "/fines/search": {
      "post": {
        "operationId": "searchFines",
        "tags": [
          "Legacy consumers"
        ],
        "summary": "Verify a fine, or list the fines of a person",
        "description": "Replaces ZIGS /Fines/VerifyById, /Fines/Search and /Fines/GetFinesHistoryByNRC (ZamMobile), read-only. Needs the fines register (FINES_REGISTER_CODE) in the register scope of the client; 404 when it is not.",
        "security": [
          {
            "clientCredentials": [
              "fines:read"
            ]
          }
        ],
        "x-required-scope": "fines:read",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FineList"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FineQuery"
              }
            }
          }
        }
      }
    },
    "/ussd/cases/lookup": {
      "post": {
        "operationId": "ussdCaseLookup",
        "tags": [
          "Legacy consumers"
        ],
        "summary": "Status and invoice of an application, for the phone of its applicant",
        "description": "Replaces ZIGS /USSD/GetCase and the read half of /USSD/CasePayment (Zamtel USSD gateway). Cases of the MDAs of the client only; a phone number that is not on the application answers 404. The service directory is the public GET /api/ussd/departments.",
        "security": [
          {
            "clientCredentials": [
              "ussd:gateway"
            ]
          }
        ],
        "x-required-scope": "ussd:gateway",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UssdCase"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorised"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UssdCaseQuery"
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "case.submitted": {
      "post": {
        "operationId": "webhook_case_submitted",
        "summary": "An application was submitted to the office.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "case.submitted"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "case.status_changed": {
      "post": {
        "operationId": "webhook_case_status_changed",
        "summary": "An application moved to a new stage the applicant can see.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "case.status_changed"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "case.returned": {
      "post": {
        "operationId": "webhook_case_returned",
        "summary": "An application was returned to the applicant for action.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "case.returned"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "case.decided": {
      "post": {
        "operationId": "webhook_case_decided",
        "summary": "An application was approved or rejected.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "case.decided"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "case.completed": {
      "post": {
        "operationId": "webhook_case_completed",
        "summary": "An application was completed.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "case.completed"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "payment.invoiced": {
      "post": {
        "operationId": "webhook_payment_invoiced",
        "summary": "A fee was requested for an application.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "payment.invoiced"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "payment.confirmed": {
      "post": {
        "operationId": "webhook_payment_confirmed",
        "summary": "A payment for an application was confirmed.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "payment.confirmed"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "permit.issued": {
      "post": {
        "operationId": "webhook_permit_issued",
        "summary": "A permit, licence or certificate was issued.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "permit.issued"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "permit.status_changed": {
      "post": {
        "operationId": "webhook_permit_status_changed",
        "summary": "A permit was suspended, reinstated, cancelled or revoked.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "permit.status_changed"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "service.published": {
      "post": {
        "operationId": "webhook_service_published",
        "summary": "A new version of a service was published to the catalogue.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "service.published"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "webhook.test": {
      "post": {
        "operationId": "webhook_webhook_test",
        "summary": "A test message sent from the back office.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "webhook.test"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "platform.module-changed": {
      "post": {
        "operationId": "webhook_platform_module-changed",
        "summary": "An optional module was switched on or off, or assigned to other ministries (MOD-02).",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "platform.module-changed"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "forestry.licence.issued": {
      "post": {
        "operationId": "webhook_forestry_licence_issued",
        "summary": "An event of the forestry module.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "forestry.licence.issued"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "forestry.licence.expired": {
      "post": {
        "operationId": "webhook_forestry_licence_expired",
        "summary": "An event of the forestry module.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "forestry.licence.expired"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "forestry.licence.suspended": {
      "post": {
        "operationId": "webhook_forestry_licence_suspended",
        "summary": "An event of the forestry module.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "forestry.licence.suspended"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "forestry.licence.revoked": {
      "post": {
        "operationId": "webhook_forestry_licence_revoked",
        "summary": "An event of the forestry module.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "forestry.licence.revoked"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "forestry.licence.reinstated": {
      "post": {
        "operationId": "webhook_forestry_licence_reinstated",
        "summary": "An event of the forestry module.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "forestry.licence.reinstated"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    },
    "forestry.checkpoint.scanned": {
      "post": {
        "operationId": "webhook_forestry_checkpoint_scanned",
        "summary": "An event of the forestry module.",
        "tags": [
          "Events"
        ],
        "parameters": [
          {
            "name": "X-GSB-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Event-Type",
            "in": "header",
            "required": true,
            "schema": {
              "const": "forestry.checkpoint.scanned"
            }
          },
          {
            "name": "X-GSB-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-GSB-Delivery-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/cloudevents+json": {
              "schema": {
                "$ref": "#/components/schemas/CloudEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Any 2xx acknowledges the delivery. 5xx, 408, 425, 429 and timeouts are retried for about 22 hours; other 4xx are not retried."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "clientCredentials": {
        "type": "oauth2",
        "description": "OAuth 2.0 client credentials. Scopes are granted per client by an administrator.",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "/api/v1/oauth/token",
            "scopes": {
              "services:read": "Read the service catalogue",
              "permits:verify": "Verify permits and licences",
              "documents:validate": "Check the electronic seal of PDF documents (bulk verification; files are not kept)",
              "registers:read": "Read National Data Register entries in its register scope",
              "cases:read": "Read the status of applications in its MDA scope",
              "events:subscribe": "Receive webhooks for events in its MDA scope",
              "audit:read": "Read the audit trail of applications in its MDA scope, from a sequence number on (no personal data)",
              "geo:read": "Read the GeoJSON feeds the platform publishes (e.g. licensed areas; no personal data)",
              "legacy:documents": "ZamPoint routes: download or view issued documents of the ministries in its MDA scope",
              "legacy:data-exchange": "ZamPoint DataExchange SetData for the ministries in its MDA scope",
              "legacy:payment-callback": "ZamPoint payment callback (/payment/callback) for the ministries in its MDA scope",
              "legacy:notify": "POST /Notify: trigger the applicant's notice of a case's step, for cases of the ministries in its MDA scope",
              "parties:read": "Read the organisations a person (by NRC) is an approved representative of (ZamPass associated entities)",
              "fines:read": "Verify fines, and read the fine history of a person, from the fines register in its register scope (ZamMobile)",
              "ussd:gateway": "Look up the status and invoice of an application for the phone number of its applicant, in its MDA scope (USSD gateway)",
              "permits:consume": "Record the use of a certificate (quantity drawn, place, consignment) and read its remaining quantity, for certificates of the ministries in its MDA scope"
            }
          }
        }
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 7807 problem details, plus the platform's message / code / requestId. Act on `code`, never on the text.",
        "required": [
          "status",
          "code",
          "message"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "code": {
            "type": "string",
            "examples": [
              "INSUFFICIENT_SCOPE",
              "RATE_LIMITED",
              "NOT_FOUND",
              "INVALID_TOKEN"
            ]
          },
          "detail": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "requestId": {
            "type": "string",
            "description": "Quote this to support."
          },
          "instance": {
            "type": "string",
            "description": "The path of the request this answers (never its query string)."
          }
        }
      },
      "OAuthError": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "enum": [
              "invalid_client",
              "unsupported_grant_type",
              "access_denied",
              "slow_down",
              "server_error"
            ]
          },
          "error_description": {
            "type": "string"
          },
          "requestId": {
            "type": "string"
          }
        }
      },
      "TokenRequest": {
        "type": "object",
        "required": [
          "grant_type"
        ],
        "properties": {
          "grant_type": {
            "const": "client_credentials"
          },
          "client_id": {
            "type": "string"
          },
          "client_secret": {
            "type": "string"
          },
          "scope": {
            "type": "string",
            "description": "Space-separated subset of the client's scopes; omit for all of them."
          }
        }
      },
      "TokenResponse": {
        "type": "object",
        "required": [
          "access_token",
          "token_type",
          "expires_in"
        ],
        "properties": {
          "access_token": {
            "type": "string"
          },
          "token_type": {
            "const": "Bearer"
          },
          "expires_in": {
            "type": "integer",
            "examples": [
              900
            ]
          },
          "scope": {
            "type": "string"
          },
          "warning": {
            "type": "string"
          }
        }
      },
      "Me": {
        "type": "object",
        "properties": {
          "clientId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "environment": {
            "type": "string",
            "enum": [
              "sandbox",
              "production"
            ]
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "services:read",
                "permits:verify",
                "documents:validate",
                "registers:read",
                "cases:read",
                "events:subscribe",
                "audit:read",
                "geo:read",
                "legacy:documents",
                "legacy:data-exchange",
                "legacy:payment-callback",
                "legacy:notify",
                "parties:read",
                "fines:read",
                "ussd:gateway",
                "permits:consume"
              ]
            }
          },
          "mdaScope": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "registerScope": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "rateLimitPerMin": {
            "type": "integer"
          },
          "dailyQuota": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "Mda": {
        "type": [
          "object",
          "null"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "shortName": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Service": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "type": [
              "string",
              "null"
            ]
          },
          "mdaId": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "mda": {
            "$ref": "#/components/schemas/Mda"
          },
          "fee": {
            "type": [
              "string",
              "null"
            ]
          },
          "processingTime": {
            "type": [
              "string",
              "null"
            ]
          },
          "validity": {
            "type": [
              "string",
              "null"
            ]
          },
          "version": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The published version number."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ServiceList": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "services": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Service"
            }
          }
        }
      },
      "ServiceDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Service"
          },
          {
            "type": "object",
            "properties": {
              "whoCanApply": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "eligibilityRequirements": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "legalReferences": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "feeSchedule": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "title": {
                      "type": "string"
                    },
                    "amount": {
                      "type": [
                        "number",
                        "null"
                      ]
                    },
                    "currency": {
                      "type": "string"
                    },
                    "basis": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "caseType": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              },
              "supportingDocuments": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "required": {
                      "type": "boolean"
                    },
                    "description": {
                      "type": "string"
                    }
                  }
                }
              },
              "steps": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "step": {
                      "type": [
                        "integer",
                        "string"
                      ]
                    },
                    "role": {
                      "type": "string"
                    },
                    "task": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "PermitVerification": {
        "type": "object",
        "required": [
          "valid"
        ],
        "properties": {
          "valid": {
            "type": "boolean",
            "description": "true only when the permit exists, is active and within its validity."
          },
          "permitNumber": {
            "type": "string"
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "examples": [
              "active",
              "expired",
              "suspended",
              "revoked",
              "cancelled"
            ]
          },
          "caseType": {
            "type": [
              "string",
              "null"
            ]
          },
          "issuedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "validFrom": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "validUntil": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "holder": {
            "type": [
              "string",
              "null"
            ],
            "description": "Initials and surname only."
          },
          "holderIdentifier": {
            "type": [
              "string",
              "null"
            ],
            "description": "Masked."
          },
          "issuer": {
            "type": [
              "string",
              "null"
            ]
          },
          "service": {
            "type": [
              "string",
              "null"
            ]
          },
          "verifiedAt": {
            "type": "string",
            "format": "date-time"
          },
          "backCaptured": {
            "type": "boolean",
            "description": "A historical paper permit recorded by the office (LP-ZIGS-14). Until a second officer validates it, its status is pending-validation and valid is false."
          }
        }
      },
      "CertificateUseRequest": {
        "type": "object",
        "required": [
          "reference",
          "place"
        ],
        "description": "Send an Idempotency-Key header: the same key with the same body is recorded once (a repeat answers 200 with replayed: true); the same key with another body is refused (422 IDEMPOTENCY_KEY_REUSED).",
        "properties": {
          "quantity": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Required when the certificate was granted for a quantity (authorised is not null); at most three decimals."
          },
          "unit": {
            "type": "string",
            "description": "Optional; when given it must be the unit of the certificate."
          },
          "reference": {
            "type": "string",
            "maxLength": 120,
            "description": "What it was used for: the consignment, declaration or entry number."
          },
          "place": {
            "type": "string",
            "maxLength": 160,
            "description": "The border post, port or checkpoint."
          },
          "officerRef": {
            "type": "string",
            "maxLength": 80,
            "description": "The service number of your officer (never shown to the holder)."
          },
          "usedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When it was used (default: now; never in the future)."
          },
          "note": {
            "type": "string",
            "maxLength": 500
          }
        }
      },
      "CertificateUse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "quantity": {
            "type": [
              "number",
              "null"
            ]
          },
          "unit": {
            "type": [
              "string",
              "null"
            ]
          },
          "reference": {
            "type": "string"
          },
          "place": {
            "type": "string"
          },
          "usedAt": {
            "type": "string",
            "format": "date-time"
          },
          "recordedBy": {
            "type": "string",
            "description": "The agency that recorded it."
          },
          "channel": {
            "enum": [
              "api",
              "office"
            ]
          },
          "status": {
            "enum": [
              "recorded",
              "reversed"
            ]
          },
          "officerRef": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "CertificateUses": {
        "type": "object",
        "description": "Whether the certificate can be used now, how much of its authorised quantity is left, and its uses (newest first).",
        "properties": {
          "permit": {
            "$ref": "#/components/schemas/PermitVerification"
          },
          "usable": {
            "type": "boolean"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "CERTIFICATE_NOT_VALID",
              "CERTIFICATE_NOT_YET_VALID"
            ]
          },
          "authorised": {
            "type": [
              "number",
              "null"
            ],
            "description": "null: the certificate has no quantity; uses are recorded as a log."
          },
          "unit": {
            "type": [
              "string",
              "null"
            ]
          },
          "used": {
            "type": [
              "number",
              "null"
            ]
          },
          "remaining": {
            "type": [
              "number",
              "null"
            ]
          },
          "singleUse": {
            "type": "boolean"
          },
          "usedUp": {
            "type": "boolean"
          },
          "count": {
            "type": "integer"
          },
          "uses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CertificateUse"
            }
          }
        }
      },
      "CertificateUseRecorded": {
        "type": "object",
        "description": "201 on a new use, 200 with replayed: true on a repeat with the same Idempotency-Key. 409 CERTIFICATE_NOT_VALID / CERTIFICATE_NOT_YET_VALID / CERTIFICATE_USED_UP / QUANTITY_EXCEEDED (remaining, requested, unit) when it cannot be used.",
        "properties": {
          "use": {
            "$ref": "#/components/schemas/CertificateUse"
          },
          "authorised": {
            "type": [
              "number",
              "null"
            ]
          },
          "used": {
            "type": [
              "number",
              "null"
            ]
          },
          "remaining": {
            "type": [
              "number",
              "null"
            ]
          },
          "unit": {
            "type": [
              "string",
              "null"
            ]
          },
          "usedUp": {
            "type": "boolean"
          },
          "replayed": {
            "type": "boolean"
          }
        }
      },
      "HubVerification": {
        "type": "object",
        "required": [
          "found",
          "valid",
          "reason"
        ],
        "description": "The national verification hub (LP-INT-06): the same answer for a document of this platform, of a peer node or of a legacy ministry ZamPoint.",
        "properties": {
          "found": {
            "type": "boolean"
          },
          "valid": {
            "type": "boolean",
            "description": "true only when the document exists and is valid now."
          },
          "status": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "active",
              "expired",
              "suspended",
              "revoked",
              "cancelled"
            ]
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              null,
              "expired",
              "revoked",
              "suspended",
              "cancelled",
              "not_valid",
              "not_found",
              "ambiguous"
            ],
            "description": "ambiguous (409): two nodes hold a document with this number - give issuer."
          },
          "documentNumber": {
            "type": "string"
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "issuer": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "code": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "issuedAt": {
            "type": [
              "string",
              "null"
            ]
          },
          "validUntil": {
            "type": [
              "string",
              "null"
            ]
          },
          "holderMasked": {
            "type": [
              "string",
              "null"
            ],
            "description": "Initials and surname only; null for a legacy ministry."
          },
          "source": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              null,
              "local",
              "federation",
              "zampoint"
            ]
          },
          "checkedAt": {
            "type": "string",
            "format": "date-time"
          },
          "node": {
            "type": "object",
            "description": "source federation: the node that answered (lane verifyhub).",
            "properties": {
              "key": {
                "type": "string"
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      },
      "BulkVerifyRequest": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 200,
            "description": "At most VERIFY_BULK_MAX_ITEMS (20). A code needs permits:verify, a PDF documents:validate.",
            "items": {
              "type": "object",
              "properties": {
                "ref": {
                  "type": "string",
                  "maxLength": 64,
                  "description": "Your reference, echoed back."
                },
                "code": {
                  "type": "string",
                  "description": "Verification code (QR) or document number."
                },
                "pdf": {
                  "type": "string",
                  "contentEncoding": "base64",
                  "description": "The PDF, at most VERIFY_UPLOAD_MAX_BYTES (10 MB). Not kept."
                }
              }
            }
          }
        }
      },
      "VerificationResult": {
        "type": "object",
        "description": "One verification answer (lib/verification/result.js): seal validity and document status side by side.",
        "properties": {
          "outcome": {
            "type": "string",
            "enum": [
              "valid",
              "warning",
              "invalid",
              "unknown",
              "not-signed"
            ]
          },
          "headline": {
            "type": "string"
          },
          "points": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string"
                },
                "tone": {
                  "type": "string",
                  "enum": [
                    "ok",
                    "warn",
                    "bad",
                    "info"
                  ]
                },
                "text": {
                  "type": "string"
                },
                "params": {
                  "type": "object"
                }
              }
            }
          },
          "seal": {
            "type": [
              "object",
              "null"
            ]
          },
          "changed": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "record": {
            "type": [
              "object",
              "null"
            ],
            "description": "The issued record the file matches - never holder data."
          },
          "signatures": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "technical": {
            "type": "object",
            "properties": {
              "indication": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "TOTAL-PASSED",
                  "INDETERMINATE",
                  "TOTAL-FAILED",
                  null
                ]
              },
              "subIndication": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "level": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "documentSha256": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      },
      "BulkVerifyResponse": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "ref": {
                  "type": "string"
                },
                "status": {
                  "type": "integer",
                  "description": "200, or the status this item alone would have had (400, 403, 404, 413, 422, 503)."
                },
                "result": {
                  "description": "For a PDF a VerificationResult; for a code the permit verification with its `validation` (a VerificationResult)."
                },
                "error": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "checkedAt": {
            "type": "string",
            "format": "date-time"
          },
          "id": {
            "type": "string"
          }
        }
      },
      "RegisterList": {
        "type": "object",
        "properties": {
          "registers": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string"
                },
                "pathCode": {
                  "type": "string",
                  "description": "The code as written in a path (/ becomes __)."
                },
                "name": {
                  "type": "string"
                },
                "description": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "category": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "rowCount": {
                  "type": "integer"
                },
                "updatedAt": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        }
      },
      "RegisterEntry": {
        "type": "object",
        "properties": {
          "register": {
            "type": "string"
          },
          "key": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "context": {
            "type": [
              "string",
              "null"
            ]
          },
          "data": {
            "type": [
              "object",
              "null"
            ],
            "description": "On a typed register: the record as the register pack describes it, only the fields the scope of the client clears."
          },
          "masked": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Typed registers: pack paths shown masked."
          },
          "withheld": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Typed registers: pack paths left out."
          },
          "schema": {
            "type": "object",
            "properties": {
              "pack": {
                "type": "string"
              },
              "version": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PartyLinks": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string"
          },
          "links": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "register": {
                  "type": "string"
                },
                "registerName": {
                  "type": "string"
                },
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "context": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "identifierType": {
                  "type": "string"
                },
                "role": {
                  "type": "string",
                  "examples": [
                    "self",
                    "founder",
                    "owner",
                    "holder",
                    "office-bearer"
                  ]
                },
                "subject": {
                  "type": "string",
                  "enum": [
                    "person",
                    "organisation",
                    "asset"
                  ]
                },
                "validFrom": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date"
                },
                "validTo": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date"
                },
                "current": {
                  "type": "boolean"
                }
              }
            }
          }
        }
      },
      "RegisterChanges": {
        "type": "object",
        "description": "Sent as canonical JSON (keys sorted, no white space) and signed: the X-GSB-JWS header is a detached compact JWS (ES256) over those exact bytes; the key is in /.well-known/jwks.json (by kid).",
        "properties": {
          "register": {
            "type": "string"
          },
          "cursor": {
            "type": "string",
            "description": "The cursor asked with."
          },
          "nextCursor": {
            "type": "string",
            "description": "Send it as ?cursor= next time; it never goes back."
          },
          "more": {
            "type": "boolean",
            "description": "true: ask again at once, there is more."
          },
          "changes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "cursor": {
                  "type": "string",
                  "description": "The position of this change in the feed."
                },
                "op": {
                  "type": "string",
                  "enum": [
                    "create",
                    "update",
                    "tombstone",
                    "restore",
                    "delete"
                  ]
                },
                "key": {
                  "type": "string"
                },
                "at": {
                  "type": "string",
                  "format": "date-time"
                },
                "state": {
                  "type": "string",
                  "enum": [
                    "present",
                    "removed"
                  ],
                  "description": "The entry as it stands now: apply `entry` (present) or remove the key (removed)."
                },
                "entry": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/RegisterEntry"
                    },
                    {
                      "type": "null"
                    }
                  ],
                  "description": "The entry now, projected for the client like /entries; null when removed."
                }
              }
            }
          }
        }
      },
      "RegisterLookup": {
        "type": "object",
        "properties": {
          "register": {
            "type": "string"
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "context": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          }
        }
      },
      "CaseStatus": {
        "type": "object",
        "required": [
          "caseNumber",
          "status"
        ],
        "properties": {
          "caseNumber": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "description": "The internal status code."
          },
          "statusLabel": {
            "type": "string",
            "description": "The words the applicant sees."
          },
          "decision": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "approved",
              "rejected",
              null
            ]
          },
          "service": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "The service version the application was submitted under."
              }
            }
          },
          "submittedAt": {
            "type": "string",
            "format": "date-time"
          },
          "dueAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "GeoFeedList": {
        "type": "object",
        "required": [
          "feeds"
        ],
        "properties": {
          "feeds": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "href": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "GeoFeatureCollection": {
        "type": "object",
        "required": [
          "type",
          "features",
          "numberReturned",
          "links"
        ],
        "description": "GeoJSON (RFC 7946), WGS 84 longitude / latitude. Paged like OGC API - Features: follow the link with rel \"next\".",
        "properties": {
          "type": {
            "const": "FeatureCollection"
          },
          "name": {
            "type": "string"
          },
          "crs": {
            "type": "object"
          },
          "numberMatched": {
            "type": [
              "integer",
              "null"
            ]
          },
          "numberReturned": {
            "type": "integer"
          },
          "features": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "const": "Feature"
                },
                "id": {
                  "type": "string"
                },
                "geometry": {
                  "type": [
                    "object",
                    "null"
                  ]
                },
                "properties": {
                  "type": "object"
                }
              }
            }
          },
          "links": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "rel": {
                  "type": "string"
                },
                "type": {
                  "type": "string"
                },
                "href": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "AuditEventPage": {
        "type": "object",
        "required": [
          "events",
          "nextAfter"
        ],
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "sequence": {
                  "type": "integer",
                  "description": "Increasing; store the last one and pass it as `after`."
                },
                "at": {
                  "type": "string",
                  "format": "date-time"
                },
                "eventType": {
                  "type": "string"
                },
                "category": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "outcome": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "enum": [
                    "success",
                    "denied",
                    "failed",
                    null
                  ]
                },
                "objectType": {
                  "type": "string"
                },
                "objectId": {
                  "type": "string"
                },
                "caseNumber": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "channel": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "actorRole": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "actorRoles": {
                  "type": [
                    "array",
                    "null"
                  ],
                  "items": {
                    "type": "string"
                  }
                },
                "classification": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "enum": [
                    "PUBLIC",
                    "INTERNAL",
                    "CONFIDENTIAL",
                    "RESTRICTED",
                    null
                  ]
                },
                "chain": {
                  "type": [
                    "object",
                    "null"
                  ]
                }
              }
            }
          },
          "nextAfter": {
            "type": "integer",
            "description": "Pass as `after` for the next page (the same value when nothing new)."
          },
          "more": {
            "type": "boolean"
          }
        }
      },
      "EventType": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "fields": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "EventCatalogue": {
        "type": "object",
        "properties": {
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventType"
            }
          }
        }
      },
      "SubscriptionList": {
        "type": "object",
        "properties": {
          "subscriptions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "events": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "active",
                    "paused"
                  ]
                },
                "createdAt": {
                  "type": "string",
                  "format": "date-time"
                }
              }
            }
          }
        }
      },
      "CloudEvent": {
        "type": "object",
        "description": "CloudEvents 1.0, structured JSON mode. Identifiers and statuses only - fetch details with your own token.",
        "required": [
          "specversion",
          "id",
          "source",
          "type",
          "time",
          "data"
        ],
        "properties": {
          "specversion": {
            "const": "1.0"
          },
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "The same on every retry and replay: use it to drop duplicates."
          },
          "source": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "time": {
            "type": "string",
            "format": "date-time"
          },
          "datacontenttype": {
            "const": "application/json"
          },
          "data": {
            "type": "object",
            "properties": {
              "caseId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "caseNumber": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "serviceId": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "status": {
                "type": "string"
              },
              "statusLabel": {
                "type": "string"
              },
              "decision": {
                "type": "string",
                "enum": [
                  "approved",
                  "rejected"
                ]
              },
              "permitNumber": {
                "type": "string"
              },
              "permitStatus": {
                "type": "string"
              },
              "serviceName": {
                "type": "string"
              },
              "version": {
                "type": "integer"
              },
              "previousVersion": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "occurredAt": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        }
      },
      "NrcQuery": {
        "type": "object",
        "required": [
          "nrc"
        ],
        "description": "The NRC travels in the body, never the URL.",
        "properties": {
          "nrc": {
            "type": "string",
            "examples": [
              "123456/78/1"
            ]
          }
        }
      },
      "AssociatedEntities": {
        "type": "object",
        "description": "Organisations the person is an active, approved representative of. Field names follow the legacy ZIGS Corporate/GetAssociatedEntities answer.",
        "properties": {
          "entities": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "entityName": {
                  "type": "string"
                },
                "entityNumber": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "PACRA registration number"
                },
                "positions": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "basis": {
                  "type": "string",
                  "enum": [
                    "staff-approved",
                    "pacra-verified"
                  ]
                },
                "verified": {
                  "type": "boolean"
                }
              }
            }
          },
          "source": {
            "const": "mandates"
          }
        }
      },
      "FineQuery": {
        "type": "object",
        "description": "Either fineId or nrc. Personal identifiers travel in the body, never the URL.",
        "properties": {
          "fineId": {
            "type": "string"
          },
          "nrc": {
            "type": "string"
          }
        }
      },
      "FineList": {
        "type": "object",
        "description": "Fines from the fines register (no names, NRCs or officer identities).",
        "properties": {
          "register": {
            "type": "string"
          },
          "fines": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "fineId": {
                  "type": "string"
                },
                "type": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "offence": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "amount": {
                  "type": [
                    "number",
                    "null"
                  ]
                },
                "currency": {
                  "type": "string"
                },
                "status": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "issuedAt": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "paidAt": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "station": {
                  "type": [
                    "string",
                    "null"
                  ]
                }
              }
            }
          }
        }
      },
      "UssdCaseQuery": {
        "type": "object",
        "required": [
          "caseNumber",
          "msisdn"
        ],
        "properties": {
          "caseNumber": {
            "type": "string"
          },
          "msisdn": {
            "type": "string",
            "description": "The number the citizen dials from (260...); must be the one on the application."
          }
        }
      },
      "UssdCase": {
        "type": "object",
        "properties": {
          "caseNumber": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "statusLabel": {
            "type": "string"
          },
          "service": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "invoice": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "invoiceNumber": {
                "type": "string"
              },
              "amount": {
                "type": "number"
              },
              "currency": {
                "const": "ZMW"
              },
              "status": {
                "type": "string"
              },
              "paid": {
                "type": "boolean"
              },
              "paidAt": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "expiresAt": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request is not valid (code VALIDATION_FAILED).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Unauthorised": {
        "description": "No token, an invalid or expired token, or the client is suspended / revoked / expired (TOKEN_REQUIRED, INVALID_TOKEN, CLIENT_INACTIVE, CLIENT_EXPIRED).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The token lacks the scope (INSUFFICIENT_SCOPE), the address is not on the client's allow-list (IP_NOT_ALLOWED), or the client has no MDA scope (MDA_SCOPE_REQUIRED).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "NotFound": {
        "description": "Not found, or outside the client's scope (the two are not distinguished).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "The client's per-minute limit or daily quota is used up (RATE_LIMITED, QUOTA_EXCEEDED). Wait Retry-After seconds.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "ServerError": {
        "description": "Something failed on our side; quote requestId.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      }
    }
  }
}