{
  "openapi": "3.1.0",
  "info": {
    "description": "MOCK DATA: responses from this deployment are produced by the Edu-V mock adapter and are fictitious.\n\nAPI for ordering, crediting, specifying, correcting, and activating learning material licenses\nbetween a distributor and the supplier of learning materials.\n\n# Idempotency\nEvery state-changing operation (POST, PATCH, DELETE) is idempotent on its\n`requestReferenceId`. If a client does not receive a response (e.g. on a\ntimeout), it must retry with the exact same `requestReferenceId` and the\nexact same payload:\n- Same `requestReferenceId` + identical payload → the original result is\n  returned again (no duplicate processing).\n- Same `requestReferenceId` + a different payload → `400 Bad Request`,\n  since the request is ambiguous with the previously stored one.\n\nAll operations are synchronous: a `200` response means the transaction has\nalready been fully processed, and `responseReferenceId` identifies that\ncompleted transaction (there is no separate \"pending\" state to poll for).\n",
    "title": "EduSaaS API",
    "version": "0.7.0",
    "x-edu-v-data-source": "mock",
    "x-edu-v-deviations": [
      {
        "id": "AUTH-001",
        "kind": "added status",
        "upstreamAsk": "Document 401 and 403.",
        "what": "401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
      },
      {
        "id": "AUTH-002",
        "kind": "subset",
        "toggle": "auth.basic.enabled",
        "upstreamAsk": "Sign off on basicAuth being disabled.",
        "what": "The spec's basicAuth alternative is disabled by default; only oauth2M2M bearer tokens are accepted."
      },
      {
        "id": "MARK-001",
        "kind": "added header",
        "upstreamAsk": "Accept the header.",
        "what": "X-Edu-V-Data-Source: mock | mixed | live | none on every response."
      },
      {
        "id": "MARK-002",
        "kind": "added header",
        "upstreamAsk": "Accept the headers.",
        "what": "X-Edu-V-Adapter, X-Edu-V-Environment, Link rel=describedby, X-Request-Id and Cache-Control no-store on every response; X-Edu-V-Auth dev-bypass in development and test only."
      },
      {
        "id": "MARK-003",
        "kind": "added property",
        "toggle": "markers.body",
        "upstreamAsk": "Accept unknown properties.",
        "what": "Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items."
      },
      {
        "id": "TOL-001",
        "kind": "tolerance",
        "toggle": "contract.null_as_absent",
        "what": "An explicit null on an optional property is treated as absent."
      },
      {
        "id": "STR-001",
        "kind": "stricter",
        "toggle": "validation.rules.STR-001",
        "upstreamAsk": "Add minItems: 1.",
        "what": "orderLines has at least one item (shadow by default)."
      },
      {
        "id": "STR-002",
        "kind": "stricter",
        "toggle": "validation.rules.STR-002",
        "upstreamAsk": "Add minimum: 1.",
        "what": "OrderLine.quantity and CreditOrderLine.quantity are at least 1 (shadow by default)."
      },
      {
        "id": "STR-003",
        "kind": "stricter",
        "toggle": "validation.rules.STR-003",
        "upstreamAsk": "Add minItems: 1.",
        "what": "An explicit CreditOrderRequest.orderLines is not empty (shadow by default)."
      },
      {
        "id": "STR-004",
        "kind": "stricter",
        "toggle": "validation.rules.STR-004",
        "upstreamAsk": "Add minLength: 1.",
        "what": "Required identifiers are not blank (shadow by default)."
      },
      {
        "id": "STR-005",
        "kind": "stricter",
        "toggle": "validation.rules.STR-005",
        "upstreamAsk": "Add uniqueItems.",
        "what": "No duplicate purchaseOrderLineId or salesOrderLineId within one order or credit request, no duplicate userIds (shadow by default)."
      },
      {
        "id": "STR-006",
        "kind": "stricter",
        "toggle": "validation.rules.STR-006",
        "upstreamAsk": "Add maxLength and maxItems.",
        "what": "Strings at most 255 characters, arrays at most 1000 items (shadow by default; review against real ECK-ID lengths before enforcing)."
      },
      {
        "id": "INT-001",
        "kind": "stricter",
        "upstreamAsk": "Confirm that integral floats are not integers.",
        "what": "A request integer must be written as a JSON integer: 2.0 or 1e2 answers 422 \"The value must be an integer.\", although JSON Schema 2020-12 counts a number with a zero fraction as an integer."
      },
      {
        "id": "INT-002",
        "kind": "stricter",
        "upstreamAsk": "Add format: int32 (or a maximum) to the integer properties.",
        "what": "Request integers (quantity, totalQuantity, newQuantity, houseNumber) are between -2147483648 and 2147483647; outside that range they answer 422 \"The value must be at most 2147483647.\" or \"The value must be at least -2147483648.\". Always enforced: the registry stores 32-bit quantities, so the request is refused before any adapter call."
      },
      {
        "id": "HTTP-001",
        "kind": "added status",
        "what": "404 and 405 for paths and methods outside the spec, with a RestErrorResponse body and X-Edu-V-Data-Source none; a 405 carries Allow (RFC 9110)."
      },
      {
        "id": "HTTP-002",
        "kind": "mapping",
        "what": "A body over 1 MiB and a wrong Content-Type answer 400 RestErrorResponse (no 413 or 415)."
      },
      {
        "id": "HTTP-003",
        "kind": "added status",
        "upstreamAsk": "Acknowledge rate limiting.",
        "what": "429 RestErrorResponse with Retry-After from the rate limiter."
      },
      {
        "id": "CODE-001",
        "kind": "provisional",
        "toggle": "contract.credit_not_found_code",
        "upstreamAsk": "Define a code.",
        "what": "correctOrder on an unknown order answers status 50 (base ErrorResponse)."
      },
      {
        "id": "CODE-002",
        "kind": "interpretation",
        "upstreamAsk": "Add an enum.",
        "what": "correctOrder uses 12, 22 and 37 with their sibling-family meanings."
      },
      {
        "id": "CODE-003",
        "kind": "interpretation",
        "upstreamAsk": "Define the code.",
        "what": "correctOrganisationLicenseSpecification on a cancelled specification answers 23."
      },
      {
        "id": "CODE-004",
        "kind": "interpretation",
        "upstreamAsk": "Define a code.",
        "what": "correctOrder with a salesOrderLineId or purchaseOrderLineId that matches no line, or two that disagree, answers 12 \"Order line not found in the order.\"."
      },
      {
        "id": "SEM-001",
        "kind": "interpretation",
        "toggle": "activations.*",
        "upstreamAsk": "Confirm.",
        "what": "activations: startDate filters registration time, offset is inclusive, nextOffset is always present, page size 100, wait capped at 30 s, filters combine with AND."
      },
      {
        "id": "SEM-002",
        "kind": "interpretation",
        "upstreamAsk": "Confirm.",
        "what": "The idempotency namespace is global across operations; functional 400 and 404 answers are replayed."
      },
      {
        "id": "SEM-003",
        "kind": "interpretation",
        "toggle": "contract.noop_success",
        "upstreamAsk": "Confirm.",
        "what": "No-ops answer 200 without an adapter call (cancel already cancelled, block already blocked, unblock not blocked, unblock cancelled with a warning, ILF correct with the same newQuantity)."
      },
      {
        "id": "SEM-004",
        "kind": "interpretation",
        "upstreamAsk": "Add minimum: 0.",
        "what": "activations: a negative offset or wait answers 400 (the spec has no minimum); a repeated query parameter answers 400; unknown query parameters are ignored."
      },
      {
        "id": "SEM-005",
        "kind": "interpretation",
        "toggle": "idempotency.wait_secs",
        "upstreamAsk": "Confirm the retry behaviour.",
        "what": "An in-flight duplicate or business-key contention not finished after 15 s answers 500 \"Request is still being processed; retry later.\", also for a credit whose original order is still processing."
      },
      {
        "id": "SEM-006",
        "kind": "interpretation",
        "upstreamAsk": "Confirm.",
        "what": "422 and 500 answers are not stored, so their requestReferenceId may come back with a different payload and is processed normally; after idempotency pruning a registry key answers 37 even with an identical payload."
      },
      {
        "id": "SEM-007",
        "kind": "interpretation",
        "toggle": "contract.null_as_absent",
        "upstreamAsk": "Confirm.",
        "what": "\"Exact same payload\" means RFC 8785 canonical JSON after null stripping and UUID lower-casing ({\"x\":null} equals an absent x)."
      },
      {
        "id": "SEM-008",
        "kind": "interpretation",
        "upstreamAsk": "Confirm.",
        "what": "A path parameter that is not a UUID answers 400 RestErrorResponse, not 422."
      },
      {
        "id": "SEM-009",
        "kind": "interpretation",
        "upstreamAsk": "Confirm.",
        "what": "A specification of the other kind on a path (an ILF id on /user-licenses/..., an ELF id on /organisation-licenses/...) is not found (50, or 404 with 62 for block)."
      },
      {
        "id": "SPEC-DEF-001",
        "kind": "spec defect",
        "upstreamAsk": "Change to anyOf or require message in RestErrorResponse.",
        "what": "oneOf [<family>ErrorResponse, RestErrorResponse] in the five *BadRequest responses is unsatisfiable for functional bodies; tests validate against contract/test-overlay.yaml (anyOf)."
      }
    ],
    "x-edu-v-mock-scenarios": [
      {
        "operations": "createOrder, create ELF/ILF",
        "owner": "mock",
        "result": "400 status 12",
        "trigger": "`productId` starting with `UNKNOWN-` (or not in `mock.products` when `mock.strict_catalog=true`)"
      },
      {
        "operations": "create ELF/ILF",
        "owner": "mock",
        "result": "400 status 6",
        "trigger": "`organisationId` `000000`"
      },
      {
        "operations": "createOrder",
        "owner": "core",
        "result": "400 status 16",
        "trigger": "same `purchaseOrderId` + `purchaseOrderLineId` as an earlier order"
      },
      {
        "operations": "correctOrder",
        "owner": "core",
        "result": "400 status 22",
        "trigger": "credit above remaining quantity, or second full credit"
      },
      {
        "operations": "correctOrder",
        "owner": "core",
        "result": "400 status 12",
        "trigger": "credit `productId` not in the order; unknown line id"
      },
      {
        "operations": "correctOrder",
        "owner": "core",
        "result": "400 status 50 (CODE-001)",
        "trigger": "credit on unknown order"
      },
      {
        "operations": "correct ILF",
        "owner": "mock",
        "result": "400 status 22",
        "trigger": "ILF `newQuantity` below the mock activated count (`min(totalQuantity, 3)`)"
      },
      {
        "operations": "correct ILF",
        "owner": "mock",
        "result": "400 status 23",
        "trigger": "stored contractId `MOCK-NOCORRECT`"
      },
      {
        "operations": "both DELETEs",
        "owner": "mock",
        "result": "400 status 23",
        "trigger": "stored contractId `MOCK-NOCANCEL`"
      },
      {
        "operations": "both DELETEs",
        "owner": "mock",
        "result": "400 status 22",
        "trigger": "stored contractId `MOCK-CANCEL-ACTIVATED`"
      },
      {
        "operations": "block",
        "owner": "mock",
        "result": "400 status 63",
        "trigger": "stored contractId `MOCK-INACTIVE`"
      },
      {
        "operations": "cancel, unblock, correct; block",
        "owner": "core",
        "result": "400 status 50; block: 404 status 62",
        "trigger": "unknown specification"
      },
      {
        "operations": "block",
        "owner": "core",
        "result": "400 status 63",
        "trigger": "block on a cancelled specification"
      },
      {
        "operations": "every mutating operation",
        "owner": "mock",
        "result": "500 \"Simulated failure (mock adapter).\" with markers; released, a retry processes again",
        "trigger": "`contractId` `MOCK-FAIL-500` on the request or the stored record"
      },
      {
        "operations": "every mutating operation (also those without any contractId)",
        "owner": "mock",
        "result": "the same simulated 500",
        "trigger": "`requestReferenceId` starting with `4d4f434b-0500-`"
      },
      {
        "operations": "queryActivations",
        "owner": "mock",
        "result": "the same simulated 500",
        "trigger": "`startDate=1900-01-01T05:00:00Z`"
      },
      {
        "operations": "every mutating operation",
        "owner": "mock",
        "result": "latency injection, capped at the deadline",
        "trigger": "`contractId` `MOCK-SLOW-<ms>` (or `purchaseOrderId` `MOCK-SLOW-<ms>`)"
      }
    ]
  },
  "servers": [
    {
      "description": "This Edu-V deployment.",
      "url": "https://acc-eduv.boom.nl/api/edusaas/v1"
    }
  ],
  "security": [
    {
      "basicAuth": []
    },
    {
      "oauth2M2M": []
    }
  ],
  "tags": [
    {
      "description": "Order or credit learning materials.",
      "name": "Orders"
    },
    {
      "description": "Specify, cancel, block, or unblock a license entitlement for an individual user (ELF).",
      "name": "User Licenses"
    },
    {
      "description": "Specify or correct a license entitlement for an organisation (ILF).",
      "name": "Organisation Licenses"
    },
    {
      "description": "Query or receive activation events.",
      "name": "Activations"
    }
  ],
  "paths": {
    "/activations": {
      "get": {
        "description": "Supports historical replay via `offset`, and long-polling via `wait`\n(server holds the request open for up to `wait` seconds waiting for\nnew events before responding). Partners unable to replay history\nshould use the `activationEvent` webhook instead (see Webhooks).\n",
        "operationId": "queryActivations",
        "parameters": [
          {
            "description": "Only return activation events from this point in time onward.",
            "in": "query",
            "name": "startDate",
            "schema": {
              "example": "2020-10-16T12:32:28Z",
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "description": "Exact event offset to resume from (in combination with `wait`).",
            "in": "query",
            "name": "offset",
            "schema": {
              "example": 1234,
              "type": "integer"
            }
          },
          {
            "description": "Number of seconds to wait for new data to become available before responding.",
            "in": "query",
            "name": "wait",
            "schema": {
              "example": 25,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActivationEventPage"
                }
              }
            },
            "description": "Activation events matching the query (may be empty)."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "HTTP-003: 429 RestErrorResponse with Retry-After from the rate limiter."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "basicAuth": []
          },
          {
            "oauth2M2M": [
              "edusaas.license.activation"
            ]
          }
        ],
        "summary": "Query activation events, with optional historical replay and long-polling",
        "tags": [
          "Activations"
        ]
      }
    },
    "/orders": {
      "post": {
        "description": "As a `Bestelomgeving leermiddelen` place an OrderRequest at the\n`Ordersysteem leermiddelen` to purchase learning materials.\n\nThe order is processed synchronously; no separate confirmation callback\nis sent. Idempotent on `requestReferenceId`. See the top-level\nIdempotency section for retry semantics.\n",
        "operationId": "createOrder",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderResponse"
                }
              }
            },
            "description": "Order processed successfully (synchronous operation)."
          },
          "400": {
            "$ref": "#/components/responses/PlaceOrderBadRequest"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "HTTP-003: 429 RestErrorResponse with Retry-After from the rate limiter."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "basicAuth": []
          },
          {
            "oauth2M2M": [
              "edusaas.order"
            ]
          }
        ],
        "summary": "Place an order for learning materials (Order)",
        "tags": [
          "Orders"
        ]
      }
    },
    "/orders/{orderRequestReferenceId}": {
      "patch": {
        "description": "As a `Bestelomgeving leermiddelen` place a CreditOrderRequest at the\n`Ordersysteem leermiddelen` to credit the earlier OrderRequest identified\nby `orderRequestReferenceId`, the requestReferenceId of the original order.\n\nThe credit order is processed synchronously; no separate confirmation\ncallback is sent. The body's `requestReferenceId` identifies this credit\nrequest, not the original order. Idempotent on `requestReferenceId`:\nretrying the same credit for the same order with the same payload returns\nthe original result without crediting twice. Reusing the ID for another\norder or payload returns `400 Bad Request`. See the top-level Idempotency\nsection for retry semantics.\n",
        "operationId": "correctOrder",
        "parameters": [
          {
            "$ref": "#/components/parameters/OrderRequestReferenceId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreditOrderRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditOrderResponse"
                }
              }
            },
            "description": "Credit order processed successfully (synchronous operation)."
          },
          "400": {
            "$ref": "#/components/responses/OrderBadRequest"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "HTTP-003: 429 RestErrorResponse with Retry-After from the rate limiter."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "basicAuth": []
          },
          {
            "oauth2M2M": [
              "edusaas.order"
            ]
          }
        ],
        "summary": "Credit an earlier order for learning materials (CorrectieOrder)",
        "tags": [
          "Orders"
        ]
      }
    },
    "/organisation-licenses": {
      "post": {
        "description": "Idempotent on `requestReferenceId`. See the top-level Idempotency\nsection for retry semantics.\n",
        "operationId": "createOrganisationLicenseSpecification",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SpecificationILFRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/Success"
          },
          "400": {
            "$ref": "#/components/responses/SpecificationBadRequest"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "HTTP-003: 429 RestErrorResponse with Retry-After from the rate limiter."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "basicAuth": []
          },
          {
            "oauth2M2M": [
              "edusaas.license.organisation"
            ]
          }
        ],
        "summary": "Specify a license entitlement for an organisation (SpecificatieILF)",
        "tags": [
          "Organisation Licenses"
        ]
      }
    },
    "/organisation-licenses/{specificationRequestReferenceId}": {
      "delete": {
        "description": "Cancels the entire specified quantity; use PATCH to reduce instead of\ncancelling entirely. Idempotent on `requestReferenceId`: retrying the\nsame cancellation after a timeout is safe.\n",
        "operationId": "cancelOrganisationLicenseSpecification",
        "parameters": [
          {
            "$ref": "#/components/parameters/SpecificationRequestReferenceId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CancellationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/Success"
          },
          "400": {
            "$ref": "#/components/responses/CorrectionBadRequest"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "HTTP-003: 429 RestErrorResponse with Retry-After from the rate limiter."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "basicAuth": []
          },
          {
            "oauth2M2M": [
              "edusaas.license.organisation"
            ]
          }
        ],
        "summary": "Fully cancel an organisation license entitlement",
        "tags": [
          "Organisation Licenses"
        ]
      },
      "patch": {
        "description": "Idempotent on `requestReferenceId`. `newQuantity` is an absolute value,\nnot a delta, so retrying the same request after a timeout does not\nreduce the quantity twice.\n",
        "operationId": "correctOrganisationLicenseSpecification",
        "parameters": [
          {
            "$ref": "#/components/parameters/SpecificationRequestReferenceId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CorrectionILFRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/Success"
          },
          "400": {
            "$ref": "#/components/responses/CorrectionBadRequest"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "HTTP-003: 429 RestErrorResponse with Retry-After from the rate limiter."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "basicAuth": []
          },
          {
            "oauth2M2M": [
              "edusaas.license.organisation"
            ]
          }
        ],
        "summary": "Correct the quantity of an organisation license entitlement (CorrectieILF)",
        "tags": [
          "Organisation Licenses"
        ]
      }
    },
    "/user-licenses": {
      "post": {
        "description": "Idempotent on `requestReferenceId`. See the top-level Idempotency\nsection for retry semantics.\n",
        "operationId": "createUserLicenseSpecification",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SpecificationELFRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/Success"
          },
          "400": {
            "$ref": "#/components/responses/SpecificationBadRequest"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "HTTP-003: 429 RestErrorResponse with Retry-After from the rate limiter."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "basicAuth": []
          },
          {
            "oauth2M2M": [
              "edusaas.license.user"
            ]
          }
        ],
        "summary": "Specify a license entitlement for an individual user (SpecificatieELF)",
        "tags": [
          "User Licenses"
        ]
      }
    },
    "/user-licenses/{specificationRequestReferenceId}": {
      "delete": {
        "description": "Idempotent on `requestReferenceId`. Retrying the same cancellation\n(same `requestReferenceId` and payload) after a timeout is safe and\nreturns the original result; it does not cancel twice.\n",
        "operationId": "cancelUserLicenseSpecification",
        "parameters": [
          {
            "$ref": "#/components/parameters/SpecificationRequestReferenceId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CorrectionELFRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/Success"
          },
          "400": {
            "$ref": "#/components/responses/CorrectionBadRequest"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "HTTP-003: 429 RestErrorResponse with Retry-After from the rate limiter."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "basicAuth": []
          },
          {
            "oauth2M2M": [
              "edusaas.license.user"
            ]
          }
        ],
        "summary": "Cancel a previously specified user license entitlement (CorrectieELF)",
        "tags": [
          "User Licenses"
        ]
      }
    },
    "/user-licenses/{specificationRequestReferenceId}/block": {
      "post": {
        "description": "Reversibly suspends access for the entire user license specification\nwithout cancelling the entitlement. Use the unblock action to remove\nthe suspension.\n\nThe request is stored using its `requestReferenceId`. Idempotent on\n`requestReferenceId`: retrying the same action for the same specification\nwith the same payload returns the original result without reprocessing.\nReusing the ID for a different action, specification, or payload returns\n`400 Bad Request`. See the top-level Idempotency section.\n",
        "operationId": "blockUserLicenseSpecification",
        "parameters": [
          {
            "$ref": "#/components/parameters/SpecificationRequestReferenceId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CorrectionELFRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/Success"
          },
          "400": {
            "$ref": "#/components/responses/BlockBadRequest"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "404": {
            "$ref": "#/components/responses/BlockNotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "HTTP-003: 429 RestErrorResponse with Retry-After from the rate limiter."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "basicAuth": []
          },
          {
            "oauth2M2M": [
              "edusaas.license.user"
            ]
          }
        ],
        "summary": "Block a previously specified user license entitlement",
        "tags": [
          "User Licenses"
        ]
      }
    },
    "/user-licenses/{specificationRequestReferenceId}/unblock": {
      "post": {
        "description": "Removes the access suspension for the entire user license specification.\nThis does not grant additional rights, extend the license validity period,\nor restore a cancelled entitlement.\n\nThe request is stored using its `requestReferenceId`. Idempotent on\n`requestReferenceId`: retrying the same action for the same specification\nwith the same payload returns the original result without reprocessing.\nReusing the ID for a different action, specification, or payload returns\n`400 Bad Request`. See the top-level Idempotency section.\n",
        "operationId": "unblockUserLicenseSpecification",
        "parameters": [
          {
            "$ref": "#/components/parameters/SpecificationRequestReferenceId"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CorrectionELFRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/Success"
          },
          "400": {
            "$ref": "#/components/responses/CorrectionBadRequest"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge."
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              }
            },
            "description": "HTTP-003: 429 RestErrorResponse with Retry-After from the rate limiter."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "basicAuth": []
          },
          {
            "oauth2M2M": [
              "edusaas.license.user"
            ]
          }
        ],
        "summary": "Unblock a previously blocked user license entitlement",
        "tags": [
          "User Licenses"
        ]
      }
    }
  },
  "webhooks": {
    "activationEvent": {
      "post": {
        "description": "Events are sent to this webhook (to EduSaaS) when a partner cannot replay\nhistorical activation data via `/activations` and only has a\nforward-only output queue. The partner registers the EduSaaS endpoint's URL\non their own side to start sending calls; Only machine-to-machine (`oauth2M2M`)\ntokens are supported for this call by EduSaaS.\n",
        "operationId": "receiveActivationEvent",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ActivationEvent"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Event received; will be processed asynchronously."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        },
        "security": [
          {
            "oauth2M2M": [
              "edusaas.license.activation"
            ]
          }
        ],
        "summary": "Push notification for a single activation event"
      }
    }
  },
  "components": {
    "headers": {
      "Allow": {
        "description": "HTTP-001: 404 and 405 for paths and methods outside the spec, with a RestErrorResponse body and X-Edu-V-Data-Source none; a 405 carries Allow (RFC 9110).",
        "schema": {
          "type": "string"
        }
      },
      "Cache-Control": {
        "description": "MARK-002: X-Edu-V-Adapter, X-Edu-V-Environment, Link rel=describedby, X-Request-Id and Cache-Control no-store on every response; X-Edu-V-Auth dev-bypass in development and test only.",
        "schema": {
          "type": "string"
        }
      },
      "Link": {
        "description": "MARK-002: X-Edu-V-Adapter, X-Edu-V-Environment, Link rel=describedby, X-Request-Id and Cache-Control no-store on every response; X-Edu-V-Auth dev-bypass in development and test only.",
        "schema": {
          "type": "string"
        }
      },
      "Retry-After": {
        "description": "HTTP-003: 429 RestErrorResponse with Retry-After from the rate limiter.",
        "schema": {
          "type": "string"
        }
      },
      "WWW-Authenticate": {
        "description": "AUTH-001: 401 and 403 on all operations with a RestErrorResponse body and an RFC 6750 WWW-Authenticate challenge.",
        "schema": {
          "type": "string"
        }
      },
      "X-Edu-V-Adapter": {
        "description": "MARK-002: X-Edu-V-Adapter, X-Edu-V-Environment, Link rel=describedby, X-Request-Id and Cache-Control no-store on every response; X-Edu-V-Auth dev-bypass in development and test only.",
        "schema": {
          "type": "string"
        }
      },
      "X-Edu-V-Auth": {
        "description": "MARK-002: X-Edu-V-Adapter, X-Edu-V-Environment, Link rel=describedby, X-Request-Id and Cache-Control no-store on every response; X-Edu-V-Auth dev-bypass in development and test only.",
        "schema": {
          "type": "string"
        }
      },
      "X-Edu-V-Data-Source": {
        "description": "MARK-001: X-Edu-V-Data-Source: mock | mixed | live | none on every response.",
        "schema": {
          "type": "string"
        }
      },
      "X-Edu-V-Environment": {
        "description": "MARK-002: X-Edu-V-Adapter, X-Edu-V-Environment, Link rel=describedby, X-Request-Id and Cache-Control no-store on every response; X-Edu-V-Auth dev-bypass in development and test only.",
        "schema": {
          "type": "string"
        }
      },
      "X-Request-Id": {
        "description": "MARK-002: X-Edu-V-Adapter, X-Edu-V-Environment, Link rel=describedby, X-Request-Id and Cache-Control no-store on every response; X-Edu-V-Auth dev-bypass in development and test only.",
        "schema": {
          "type": "string"
        }
      }
    },
    "parameters": {
      "OrderRequestReferenceId": {
        "description": "A reference to the previous order request.",
        "in": "path",
        "name": "orderRequestReferenceId",
        "required": true,
        "schema": {
          "format": "uuid",
          "type": "string"
        }
      },
      "SpecificationRequestReferenceId": {
        "description": "A reference to the previous specification request.",
        "in": "path",
        "name": "specificationRequestReferenceId",
        "required": true,
        "schema": {
          "format": "uuid",
          "type": "string"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RestErrorResponse"
            }
          }
        },
        "description": "The request could not be decoded or was otherwise invalid."
      },
      "BlockBadRequest": {
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/BlockErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              ]
            }
          }
        },
        "description": "Block request could not be processed due to a domain error."
      },
      "BlockNotFound": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/BlockNotFoundErrorResponse"
            }
          }
        },
        "description": "Specification reference ID to block was not found."
      },
      "CorrectionBadRequest": {
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/CorrectionErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              ]
            }
          }
        },
        "description": "Correction request could not be processed due to a domain error."
      },
      "InternalError": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RestErrorResponse"
            }
          }
        },
        "description": "An unexpected error occurred."
      },
      "OrderBadRequest": {
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              ]
            }
          }
        },
        "description": "Order or credit order request was invalid or could not be processed due to a domain error."
      },
      "PlaceOrderBadRequest": {
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/OrderErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              ]
            }
          }
        },
        "description": "Order request was invalid or could not be processed due to a domain error."
      },
      "SpecificationBadRequest": {
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/SpecificationErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/RestErrorResponse"
                }
              ]
            }
          }
        },
        "description": "Specification request could not be processed due to a domain error."
      },
      "Success": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/TransactionResponse"
            }
          }
        },
        "description": "Request processed successfully (synchronous operation)."
      },
      "UnprocessableEntity": {
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ValidationErrorResponse"
            }
          }
        },
        "description": "The JSON request did not conform to the request schema."
      }
    },
    "schemas": {
      "ActivationEvent": {
        "properties": {
          "_dataSource": {
            "description": "MARK-003: Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items.",
            "enum": [
              "mock",
              "mixed"
            ],
            "type": "string"
          },
          "activationCode": {
            "description": "In case the Product has been activated by an activation code, this field contains the activation code.",
            "type": "string"
          },
          "eventId": {
            "description": "Unique identifier for the activation event (to be used as offset for pagination).",
            "type": "integer"
          },
          "expirationDate": {
            "description": "The expiration date until this Student or Employee has the right to use the Product. Format: YYYY-MM-DD (according to RFC3339).\nIn case the Entitlement specified a minExpirationDate, the expirationDate equals this minExpirationDate or lies further in the future.\nThe expirationDate allows the `Licentieregistratie` to have license periods for each individual License on an Entitlement.\n",
            "format": "date",
            "type": "string"
          },
          "organisation": {
            "$ref": "#/components/schemas/Organisation"
          },
          "specificationRequestReferenceId": {
            "description": "A reference to the previous specification request (can be a User or Organisation specification).",
            "format": "uuid",
            "type": "string"
          },
          "usageDate": {
            "description": "The date the Product has been activated. Format YYYY-MM-DD (according to RFC3339).",
            "format": "date",
            "type": "string"
          },
          "userIds": {
            "items": {
              "$ref": "#/components/schemas/UserIdentifier"
            },
            "minItems": 1,
            "type": "array"
          }
        },
        "required": [
          "eventId",
          "specificationRequestReferenceId",
          "usageDate",
          "expirationDate",
          "organisation",
          "userIds"
        ],
        "type": "object"
      },
      "ActivationEventPage": {
        "properties": {
          "_dataSource": {
            "description": "MARK-003: Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items.",
            "enum": [
              "mock",
              "mixed"
            ],
            "type": "string"
          },
          "events": {
            "items": {
              "$ref": "#/components/schemas/ActivationEvent"
            },
            "type": "array"
          },
          "nextOffset": {
            "description": "Offset to use for the next query to continue from where this page left off.",
            "type": "integer"
          }
        },
        "required": [
          "events"
        ],
        "type": "object"
      },
      "BlockErrorResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorResponse"
          },
          {
            "properties": {
              "status": {
                "description": "Functional error code:\n- 37: Request reference ID was already used.\n- 63: No active license was found for the user and specification reference ID.\n",
                "enum": [
                  37,
                  63
                ],
                "type": "integer"
              }
            },
            "type": "object"
          }
        ],
        "properties": {
          "_dataSource": {
            "description": "MARK-003: Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items.",
            "enum": [
              "mock",
              "mixed"
            ],
            "type": "string"
          }
        }
      },
      "BlockNotFoundErrorResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorResponse"
          },
          {
            "properties": {
              "status": {
                "description": "Functional error code 62: Specification reference ID to block was not found.",
                "enum": [
                  62
                ],
                "type": "integer"
              }
            },
            "type": "object"
          }
        ],
        "properties": {
          "_dataSource": {
            "description": "MARK-003: Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items.",
            "enum": [
              "mock",
              "mixed"
            ],
            "type": "string"
          }
        }
      },
      "CancellationRequest": {
        "properties": {
          "requestReferenceId": {
            "description": "Unique requestReferenceId for this request.",
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "requestReferenceId"
        ],
        "type": "object"
      },
      "CorrectionELFRequest": {
        "properties": {
          "requestReferenceId": {
            "description": "Unique requestReferenceId for this request.",
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "requestReferenceId"
        ],
        "type": "object"
      },
      "CorrectionErrorResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorResponse"
          },
          {
            "properties": {
              "status": {
                "description": "Functional error code:\n- 22: Requested quantity correction is not available.\n- 23: Quantity correction is not allowed by contract terms.\n- 37: Request reference ID was already used.\n- 50: Specification reference ID was not found.\n",
                "enum": [
                  22,
                  23,
                  37,
                  50
                ],
                "type": "integer"
              }
            },
            "type": "object"
          }
        ],
        "properties": {
          "_dataSource": {
            "description": "MARK-003: Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items.",
            "enum": [
              "mock",
              "mixed"
            ],
            "type": "string"
          }
        }
      },
      "CorrectionILFRequest": {
        "properties": {
          "newQuantity": {
            "description": "The new total quantity for this specification. This is an absolute\nvalue (not a delta), so retrying the same request is idempotent\nand does not reduce the quantity twice.\n",
            "example": 1,
            "maximum": 2147483647,
            "minimum": 1,
            "type": "integer"
          },
          "requestReferenceId": {
            "description": "Unique requestReferenceId for this request.",
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "requestReferenceId",
          "newQuantity"
        ],
        "type": "object"
      },
      "CreditOrderConfirmationLine": {
        "properties": {
          "purchaseOrderLineId": {
            "description": "Echo of the `purchaseOrderLineId` from the original OrderRequest line, when supplied, to map it to the cancelled `salesOrderLineId`.",
            "type": "string"
          },
          "salesOrderLineId": {
            "description": "Reference to the `salesOrderLineId` that has been cancelled.",
            "type": "string"
          }
        },
        "required": [
          "salesOrderLineId"
        ],
        "type": "object"
      },
      "CreditOrderLine": {
        "properties": {
          "productId": {
            "description": "The Product that is to be cancelled.",
            "type": "string"
          },
          "purchaseOrderLineId": {
            "description": "Optional reference to the `purchaseOrderLineId` of the OrderRequest for the product to be cancelled.",
            "type": "string"
          },
          "quantity": {
            "description": "The quantity of Product that is to be cancelled.",
            "example": 1,
            "maximum": 2147483647,
            "minimum": -2147483648,
            "type": "integer"
          },
          "salesOrderLineId": {
            "description": "Optional reference to the `salesOrderLineId` of the synchronous order response for the product to be cancelled.",
            "type": "string"
          }
        },
        "required": [
          "productId",
          "quantity"
        ],
        "type": "object"
      },
      "CreditOrderRequest": {
        "description": "Request sent by the `Bestelomgeving leermiddelen` to the\n`Ordersysteem leermiddelen` with a request to credit an order.\nThe original order is identified by orderRequestReferenceId in the path.\n",
        "properties": {
          "orderLines": {
            "description": "Optional specification of the products in the OrderRequest to be cancelled. If omitted, the entire order is credited.",
            "items": {
              "$ref": "#/components/schemas/CreditOrderLine"
            },
            "type": "array"
          },
          "requestReferenceId": {
            "description": "Unique requestReferenceId for this request. If a party receives\nanother request with the same requestReferenceId and identical\npayload, it returns the original synchronous response without\nprocessing the request again. See the top-level Idempotency section.\n",
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "requestReferenceId"
        ],
        "type": "object"
      },
      "CreditOrderResponse": {
        "properties": {
          "_dataSource": {
            "description": "MARK-003: Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items.",
            "enum": [
              "mock",
              "mixed"
            ],
            "type": "string"
          },
          "creditOrderConfirmationLines": {
            "description": "References to cancelled purchase and sales order lines, in the same\norder as the request's orderLines when supplied. If orderLines is\nomitted, returns references to all cancelled order lines.\n",
            "items": {
              "$ref": "#/components/schemas/CreditOrderConfirmationLine"
            },
            "type": "array"
          },
          "responseReferenceId": {
            "description": "A reference to this synchronous response sent by the `Ordersysteem leermiddelen` to the `Bestelomgeving leermiddelen`.",
            "format": "uuid",
            "type": "string"
          },
          "salesOrderId": {
            "description": "Sales order number of the order to be credited as defined by the `Ordersysteem leermiddelen`. This number is linked to the financial system of the `Ordersysteem leermiddelen`.",
            "type": "string"
          }
        },
        "required": [
          "responseReferenceId",
          "salesOrderId",
          "creditOrderConfirmationLines"
        ],
        "type": "object"
      },
      "DeliveryLocation": {
        "description": "An optional address at which warehouse location the Product (physical learning materials) should be delivered",
        "properties": {
          "city": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "countryCode": {
            "description": "According to Alpha-2 code from ISO 3166, e.g. NL",
            "type": "string"
          },
          "houseNumber": {
            "description": "The house number.",
            "maximum": 2147483647,
            "minimum": -2147483648,
            "type": "integer"
          },
          "houseNumberSuffix": {
            "description": "Additions to the house number, e.g. A or -104.",
            "type": "string"
          },
          "name": {
            "description": "To the attention of...",
            "type": "string"
          },
          "street": {
            "type": "string"
          },
          "zipCode": {
            "type": "string"
          }
        },
        "required": [
          "street",
          "houseNumber",
          "zipCode",
          "city",
          "country"
        ],
        "type": "object"
      },
      "ErrorResponse": {
        "description": "Base functional error payload; operation-specific schemas constrain the status codes.",
        "properties": {
          "_dataSource": {
            "description": "MARK-003: Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items.",
            "enum": [
              "mock",
              "mixed"
            ],
            "type": "string"
          },
          "status": {
            "description": "Functional error code, separate from the HTTP response status.",
            "type": "integer"
          },
          "statusMessage": {
            "description": "Human-readable message describing the error.",
            "type": "string"
          }
        },
        "required": [
          "status",
          "statusMessage"
        ],
        "type": "object"
      },
      "OrderConfirmationLine": {
        "properties": {
          "purchaseOrderLineId": {
            "description": "Echo of the `purchaseOrderLineId` from the original OrderRequest line, when supplied, to map it to the `salesOrderLineId`.",
            "type": "string"
          },
          "salesOrderLineId": {
            "description": "An identifier from the `Ordersysteem leermiddelen` to reference this order confirmation line.",
            "type": "string"
          }
        },
        "required": [
          "salesOrderLineId"
        ],
        "type": "object"
      },
      "OrderErrorResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorResponse"
          },
          {
            "properties": {
              "status": {
                "description": "Functional error code:\n- 12: Product does not exist.\n- 16: Purchase order ID and purchase order line ID combination was already registered as an order.\n- 37: Request reference ID was already used.\n",
                "enum": [
                  12,
                  16,
                  37
                ],
                "type": "integer"
              }
            },
            "type": "object"
          }
        ],
        "properties": {
          "_dataSource": {
            "description": "MARK-003: Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items.",
            "enum": [
              "mock",
              "mixed"
            ],
            "type": "string"
          }
        }
      },
      "OrderLine": {
        "properties": {
          "productId": {
            "description": "The Product the `Bestelomgeving leermiddelen` orders. The productId can be retrieved from the Catalogue API from the `Ordersysteem leermiddelen`.",
            "type": "string"
          },
          "purchaseOrderLineId": {
            "description": "Optional line item identifier.",
            "type": "string"
          },
          "quantity": {
            "description": "The quantity of the Product the `Bestelomgeving leermiddelen` orders.",
            "example": 1,
            "maximum": 2147483647,
            "minimum": -2147483648,
            "type": "integer"
          }
        },
        "required": [
          "productId",
          "quantity"
        ],
        "type": "object"
      },
      "OrderRequest": {
        "description": "Request sent by the `Bestelomgeving leermiddelen` to the\n`Ordersysteem leermiddelen` to place an order with quantities for learning materials.\n",
        "properties": {
          "contractId": {
            "description": "An optional unique identifier for a contract between `Ordersysteem leermiddelen` and `Bestelomgeving leermiddelen` where this request belongs to.",
            "type": "string"
          },
          "deliveryDate": {
            "description": "Optional desired deliveryDate for delivery of the Product (physical learning materials). Format: YYYY-MM-DD (according to RFC3339).",
            "example": "2022-07-31",
            "format": "date",
            "type": "string"
          },
          "deliveryLocation": {
            "$ref": "#/components/schemas/DeliveryLocation"
          },
          "orderLines": {
            "items": {
              "$ref": "#/components/schemas/OrderLine"
            },
            "type": "array"
          },
          "purchaseOrderId": {
            "description": "Purchase order number as defined by the `Bestelomgeving leermiddelen`. This number is linked to the financial system of the `Bestelomgeving leermiddelen`.",
            "type": "string"
          },
          "requestReferenceId": {
            "description": "Unique requestReferenceId for this request. If a party receives\nanother request with the same requestReferenceId and identical\npayload, it returns the original synchronous response without\nprocessing the request again. See the top-level Idempotency section.\n",
            "format": "uuid",
            "type": "string"
          },
          "schoolBuyer": {
            "$ref": "#/components/schemas/SchoolBuyer"
          }
        },
        "required": [
          "requestReferenceId",
          "purchaseOrderId",
          "orderLines"
        ],
        "type": "object"
      },
      "OrderResponse": {
        "properties": {
          "_dataSource": {
            "description": "MARK-003: Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items.",
            "enum": [
              "mock",
              "mixed"
            ],
            "type": "string"
          },
          "orderConfirmationLines": {
            "description": "Purchase and sales order line identifiers in the same order as the request's orderLines.",
            "items": {
              "$ref": "#/components/schemas/OrderConfirmationLine"
            },
            "type": "array"
          },
          "responseReferenceId": {
            "description": "A reference to this synchronous response sent by the `Ordersysteem leermiddelen` to the `Bestelomgeving leermiddelen`.",
            "format": "uuid",
            "type": "string"
          },
          "salesOrderId": {
            "description": "Sales order number as defined by the `Ordersysteem leermiddelen`. This number is linked to the financial system of the `Ordersysteem leermiddelen`.",
            "type": "string"
          }
        },
        "required": [
          "responseReferenceId",
          "salesOrderId",
          "orderConfirmationLines"
        ],
        "type": "object"
      },
      "Organisation": {
        "properties": {
          "organisationId": {
            "description": "Unique identifier of the school responsible for the order, specification, or activation: DD_ID.",
            "type": "string"
          },
          "organisationIdType": {
            "description": "Type of the organisation identifier. Currently, only \"DD_ID\" is supported.",
            "enum": [
              "DD_ID"
            ],
            "type": "string"
          }
        },
        "required": [
          "organisationId",
          "organisationIdType"
        ],
        "type": "object"
      },
      "RestErrorResponse": {
        "description": "HTTP-level error details without a functional domain code.",
        "properties": {
          "_dataSource": {
            "description": "MARK-003: Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items.",
            "enum": [
              "mock",
              "mixed"
            ],
            "type": "string"
          },
          "message": {
            "description": "Optional human-readable HTTP error message.",
            "type": "string"
          }
        },
        "type": "object"
      },
      "SchoolBuyer": {
        "properties": {
          "displayName": {
            "description": "Weergavenaam van de contactpersoon van de onderwijsorganisatie.",
            "example": "Jan Jansen",
            "type": "string"
          },
          "email": {
            "description": "E-mailadres van de contactpersoon van de onderwijsorganisatie.",
            "example": "j.jansen@deregenboog.nl",
            "format": "email",
            "type": "string"
          },
          "organisation": {
            "$ref": "#/components/schemas/Organisation"
          }
        },
        "required": [
          "displayName",
          "email",
          "organisation"
        ],
        "type": "object"
      },
      "SpecificationELFRequest": {
        "properties": {
          "contractId": {
            "description": "An optional unique identifier for a contract between the distributor and the supplier of the learning materials.",
            "type": "string"
          },
          "organisation": {
            "$ref": "#/components/schemas/Organisation"
          },
          "productId": {
            "description": "Unique identifier of a Product. The productId can be retrieved from the Catalogue API of supplier of the learning materials.",
            "type": "string"
          },
          "requestReferenceId": {
            "description": "Unique identifier for the request, unique across all specification requests (both ELF and ILF).",
            "format": "uuid",
            "type": "string"
          },
          "startDate": {
            "description": "Date from which the product can be activated by the Entitlee(s). The startDate marks the start of the activation period.\nFormat: YYYY-MM-DD (according to RFC3339).\n",
            "example": "2021-08-22",
            "format": "date",
            "type": "string"
          },
          "userIds": {
            "items": {
              "$ref": "#/components/schemas/UserIdentifier"
            },
            "minItems": 1,
            "type": "array"
          }
        },
        "required": [
          "requestReferenceId",
          "productId",
          "startDate",
          "organisation",
          "userIds"
        ],
        "type": "object"
      },
      "SpecificationErrorResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ErrorResponse"
          },
          {
            "properties": {
              "status": {
                "description": "Functional error code:\n- 6: Organisation was not found.\n- 12: Product is unavailable or does not exist.\n- 37: Request reference ID was already used.\n",
                "enum": [
                  6,
                  12,
                  37
                ],
                "type": "integer"
              }
            },
            "type": "object"
          }
        ],
        "properties": {
          "_dataSource": {
            "description": "MARK-003: Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items.",
            "enum": [
              "mock",
              "mixed"
            ],
            "type": "string"
          }
        }
      },
      "SpecificationILFRequest": {
        "properties": {
          "contractId": {
            "description": "An optional unique identifier for a contract between the distributor and the supplier of the learning materials.",
            "type": "string"
          },
          "organisation": {
            "$ref": "#/components/schemas/Organisation"
          },
          "productId": {
            "description": "Unique identifier of a Product. The productId can be retrieved from the Catalogue API of supplier of the learning materials.",
            "type": "string"
          },
          "requestReferenceId": {
            "description": "Unique identifier for the request.",
            "format": "uuid",
            "type": "string"
          },
          "startDate": {
            "description": "Date from which the product can be activated by the Entitlee(s). The startDate marks the start of the activation period.\nFormat: YYYY-MM-DD (according to RFC3339).\n",
            "example": "2021-08-22",
            "format": "date",
            "type": "string"
          },
          "totalQuantity": {
            "description": "Total quantity for this specification.",
            "example": 100,
            "maximum": 2147483647,
            "minimum": 1,
            "type": "integer"
          }
        },
        "required": [
          "requestReferenceId",
          "productId",
          "startDate",
          "organisation",
          "totalQuantity"
        ],
        "type": "object"
      },
      "TransactionResponse": {
        "properties": {
          "_dataSource": {
            "description": "MARK-003: Top-level _dataSource on adapter- and registry-backed bodies and on mock-caused 500 RestErrorResponse bodies, and on non-live ActivationEvent items.",
            "enum": [
              "mock",
              "mixed"
            ],
            "type": "string"
          },
          "responseReferenceId": {
            "description": "Unique identifier of the completed transaction.",
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "responseReferenceId"
        ],
        "type": "object"
      },
      "UserIdentifier": {
        "properties": {
          "userId": {
            "description": "Unique identifier of the user for the specification.",
            "type": "string"
          },
          "userIdType": {
            "description": "Type of the user identifier. Currently supported types are \"eckId\", \"NEPPI\", and \"NEPRI\".",
            "enum": [
              "eckId",
              "NEPPI",
              "NEPRI"
            ],
            "type": "string"
          }
        },
        "required": [
          "userId",
          "userIdType"
        ],
        "type": "object"
      },
      "ValidationErrorResponse": {
        "description": "Request validation errors generated from JSON schema constraints.",
        "properties": {
          "validation_errors": {
            "additionalProperties": {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            "description": "Validation errors grouped by request field.",
            "type": "object"
          }
        },
        "required": [
          "validation_errors"
        ],
        "type": "object"
      }
    },
    "securitySchemes": {
      "basicAuth": {
        "description": "Disabled on Edu-V unless auth.basic.enabled is set (AUTH-002).",
        "scheme": "basic",
        "type": "http"
      },
      "oauth2M2M": {
        "description": "Machine-to-machine client-credentials flow.",
        "flows": {
          "clientCredentials": {
            "scopes": {
              "edusaas.license.activation": "Query or receive activation events.",
              "edusaas.license.organisation": "Specify or correct organisation license entitlements.",
              "edusaas.license.user": "Specify, cancel, block, or unblock user license entitlements.",
              "edusaas.order": "Place orders or credit earlier orders for learning materials."
            },
            "tokenUrl": "https://acc-account.boom.nl/auth/realms/master/protocol/openid-connect/token"
          }
        },
        "type": "oauth2"
      }
    }
  }
}