{"openapi":"3.1.0","info":{"title":"marve-py-license-service","version":"0.1.0"},"paths":{"/licenses/current":{"get":{"tags":["Licenses"],"summary":"The signed-in user's licence","description":"Resolved from the token. Every product on the licence, with `held_by_me` and the seats left, which count invitations still holding one. 404 until a new purchase has been turned into a licence.","operationId":"get_current_license_licenses_current_get","responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"properties":{"license_reference":{"type":"string"},"organisation_reference":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"code":{"type":"string","nullable":true},"i_am_the_owner":{"type":"boolean"},"products":{"items":{"properties":{"product_reference":{"type":"string","nullable":true},"product_name":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"valid_from":{"type":"string","nullable":true},"valid_to":{"type":"string","nullable":true},"held_by_me":{"type":"boolean"},"features":{"items":{"additionalProperties":true,"type":"object"},"type":"array"},"seats":{"properties":{"total":{"type":"integer"},"used":{"type":"integer"},"available":{"type":"integer"}},"additionalProperties":true,"type":"object","required":["total","used","available"],"title":"Seats"}},"additionalProperties":true,"type":"object","required":["held_by_me","seats"],"title":"CurrentProduct"},"type":"array"}},"additionalProperties":true,"type":"object","required":["license_reference","i_am_the_owner","products"],"title":"CurrentLicense"},"example":{"license_reference":"11111111-1111-1111-1111-111111111111","organisation_reference":"55555555-5555-5555-5555-555555555555","status":"active","code":"ABCD-EFGH-IJKL","i_am_the_owner":true,"products":[{"product_reference":"prod-polpred","product_name":"PolPred","status":"active","valid_from":"2026-01-01","valid_to":"2027-01-01","held_by_me":true,"features":[{"feature_reference":"66666666-6666-6666-6666-666666666666","feature_name":"3D_CS20_7L","feature_type":"model","one_off":true,"prediction_window_start":"2026-01-01","prediction_window_end":"2026-12-31","hindcast_window_start":"2020-01-01","prediction_months":12,"boxes":[{"lat_min":50,"lat_max":52,"lon_min":-5,"lon_max":-3,"coverage":0.75}],"metadata":{"boundary":{"north":54,"south":50,"west":-5,"east":-3}}}],"seats":{"total":5,"used":1,"available":4}},{"product_reference":"prod-tidemorph","product_name":"TideMorph","status":"active","valid_from":"2026-01-01","valid_to":"2026-11-01","held_by_me":true,"features":[{"feature_reference":"66666666-6666-6666-6666-666666666666","feature_name":"CS3X_50HC","feature_type":"model","one_off":true,"prediction_window_start":"2026-01-01","prediction_window_end":"2026-12-31","hindcast_window_start":"2020-01-01","prediction_months":12,"boxes":[{"lat_min":50,"lat_max":52,"lon_min":-5,"lon_max":-3,"coverage":0.75}],"metadata":{"boundary":{"north":54,"south":50,"west":-5,"east":-3}}}],"seats":{"total":1,"used":1,"available":0}}]}}}},"401":{"description":"No token, an expired token, not signed in, or not allowed to make this change","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"404":{"description":"No such licence, product or model, or a licence this caller is not on (the same answer, deliberately)","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"500":{"description":"Unexpected failure. Quote `error_reference` when reporting it","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}}},"security":[{"HTTPBearer":[]}]}},"/licenses/current/models":{"get":{"tags":["Licenses"],"summary":"Models the signed-in user can use","description":"Which models the licence can be used with, filtered by place, dates and product.\n\nGeography and dates never remove a row: they set `available` and fill `reasons`. Add\n`available=true` for only the usable ones. Paged like every other listing: `page`\n(or `page=all`) and `ordering=field` / `ordering=-field`.","operationId":"get_current_models_licenses_current_models_get","parameters":[{"description":"A point: latitude in degrees. Needs `longitude`.","required":false,"schema":{"type":"string","title":"Latitude","description":"A point: latitude in degrees. Needs `longitude`.","examples":["51.0"]},"name":"latitude","in":"query"},{"description":"A point: longitude in degrees. Needs `latitude`.","required":false,"schema":{"type":"string","title":"Longitude","description":"A point: longitude in degrees. Needs `latitude`.","examples":["-4.0"]},"name":"longitude","in":"query"},{"description":"An area: all four of north, south, east, west.","required":false,"schema":{"type":"string","title":"North","description":"An area: all four of north, south, east, west."},"name":"north","in":"query"},{"description":"An area: all four of north, south, east, west.","required":false,"schema":{"type":"string","title":"South","description":"An area: all four of north, south, east, west."},"name":"south","in":"query"},{"description":"An area: all four of north, south, east, west.","required":false,"schema":{"type":"string","title":"East","description":"An area: all four of north, south, east, west."},"name":"east","in":"query"},{"description":"An area: all four of north, south, east, west.","required":false,"schema":{"type":"string","title":"West","description":"An area: all four of north, south, east, west."},"name":"west","in":"query"},{"description":"Checked against each model's own window.","required":false,"schema":{"type":"string","title":"Start Date","description":"Checked against each model's own window.","examples":["2026-03-01"]},"name":"start_date","in":"query"},{"description":"Checked against each model's own window.","required":false,"schema":{"type":"string","title":"End Date","description":"Checked against each model's own window.","examples":["2026-04-01"]},"name":"end_date","in":"query"},{"description":"Exact match.","required":false,"schema":{"type":"string","title":"Product Reference","description":"Exact match."},"name":"product_reference","in":"query"},{"description":"Partial, case-insensitive.","required":false,"schema":{"type":"string","title":"Product Name","description":"Partial, case-insensitive."},"name":"product_name","in":"query"},{"description":"Partial, case-insensitive.","required":false,"schema":{"type":"string","title":"Model Code","description":"Partial, case-insensitive."},"name":"model_code","in":"query"},{"description":"Exact match, e.g. `model`.","required":false,"schema":{"type":"string","title":"Feature Type","description":"Exact match, e.g. `model`."},"name":"feature_type","in":"query"},{"description":"`true` for only the models that can run a 3D time series, `false` for only the others.","required":false,"schema":{"type":"string","title":"Multi Layer","description":"`true` for only the models that can run a 3D time series, `false` for only the others."},"name":"multi_layer","in":"query"},{"description":"Exact match, e.g. `active`.","required":false,"schema":{"type":"string","title":"Status","description":"Exact match, e.g. `active`."},"name":"status","in":"query"},{"description":"`true` to keep only models usable under the filters given.","required":false,"schema":{"type":"string","title":"Available","description":"`true` to keep only models usable under the filters given."},"name":"available","in":"query"},{"description":"Search across every field.","required":false,"schema":{"type":"string","title":"All","description":"Search across every field."},"name":"all","in":"query"},{"description":"Whose access to report; `all` for the whole licence. Anybody but yourself needs an admin role or licence ownership.","required":false,"schema":{"type":"string","title":"User Reference","description":"Whose access to report; `all` for the whole licence. Anybody but yourself needs an admin role or licence ownership."},"name":"user_reference","in":"query"},{"description":"Page number, or `all` for no paging.","required":false,"schema":{"type":"string","title":"Page","description":"Page number, or `all` for no paging.","examples":["1"]},"name":"page","in":"query"},{"description":"`field` ascending, `-field` descending. Default `model_code`.","required":false,"schema":{"type":"string","title":"Ordering","description":"`field` ascending, `-field` descending. Default `model_code`.","examples":["-valid_to"]},"name":"ordering","in":"query"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"properties":{"license_reference":{"type":"string"},"organisation_reference":{"type":"string","nullable":true},"user_reference":{"type":"string","nullable":true},"items":{"items":{"properties":{"model_code":{"type":"string"},"feature_reference":{"type":"string","nullable":true},"feature_type":{"type":"string","nullable":true},"product_reference":{"type":"string","nullable":true},"product_name":{"type":"string","nullable":true},"license_type":{"type":"string","nullable":true},"license_class":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"valid_from":{"type":"string","nullable":true},"valid_to":{"type":"string","nullable":true},"covers_from":{"type":"string","nullable":true},"covers_to":{"type":"string","nullable":true},"prediction_months":{"type":"integer","nullable":true},"one_off":{"type":"boolean","nullable":true},"boxes":{"type":"integer","nullable":true},"boxes_matched":{"type":"integer","nullable":true},"coverage":{"type":"number","nullable":true},"boundary":{"properties":{"north":{"type":"number"},"south":{"type":"number"},"west":{"type":"number"},"east":{"type":"number"}},"additionalProperties":true,"type":"object","title":"Boundary"},"multi_layer":{"type":"boolean"},"available":{"type":"boolean"},"reasons":{"items":{"type":"string"},"type":"array"}},"additionalProperties":true,"type":"object","required":["model_code","available","reasons"],"title":"ModelRow"},"type":"array"},"pagination":{"properties":{"current_page":{"type":"integer"},"page_size":{"type":"integer"},"total_records":{"type":"integer"},"total_pages":{"type":"integer"},"has_next":{"type":"boolean"},"has_previous":{"type":"boolean"}},"additionalProperties":true,"type":"object","title":"Pagination"}},"additionalProperties":true,"type":"object","required":["license_reference","items","pagination"],"title":"ModelSearch"},"example":{"license_reference":"11111111-1111-1111-1111-111111111111","organisation_reference":"55555555-5555-5555-5555-555555555555","user_reference":"22222222-2222-2222-2222-222222222222","items":[{"model_code":"3D_CS20_7L","feature_reference":"66666666-6666-6666-6666-666666666666","feature_type":"model","product_reference":"prod-polpred","product_name":"PolPred","license_type":"subscription","license_class":"professional","status":"active","valid_from":"2026-01-01","valid_to":"2027-01-01","covers_from":"2020-01-01","covers_to":"2026-12-31","prediction_months":12,"one_off":true,"boxes":2,"boxes_matched":1,"coverage":0.75,"boundary":{"north":54,"south":50,"west":-5,"east":-3},"multi_layer":true,"available":true,"reasons":[]},{"model_code":"CS3X_50HC","feature_reference":"66666666-6666-6666-6666-666666666666","feature_type":"model","product_reference":"prod-tidemorph","product_name":"TideMorph","license_type":"trial","license_class":"professional","status":"active","valid_from":"2026-01-01","valid_to":"2026-11-01","covers_from":"2020-01-01","covers_to":"2026-12-31","prediction_months":12,"one_off":true,"boxes":1,"boundary":{"north":60,"south":58,"west":0,"east":2},"multi_layer":false,"available":false,"reasons":["the point is outside the licensed area"]}],"pagination":{"current_page":1,"page_size":10,"total_records":2,"total_pages":1,"has_next":false,"has_previous":false}}}}},"400":{"description":"A query parameter or the body is not usable, for example a latitude that is not a number","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"401":{"description":"No token, an expired token, not signed in, or not allowed to make this change","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"404":{"description":"No such licence, product or model, or a licence this caller is not on (the same answer, deliberately)","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"500":{"description":"Unexpected failure. Quote `error_reference` when reporting it","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/licenses/health":{"get":{"tags":["Licenses"],"summary":"Health check","operationId":"health_licenses_health_get","responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"properties":{"message":{"type":"string"}},"additionalProperties":true,"type":"object","required":["message"],"title":"Health"},"example":{"message":"marve-py-license-service is okay and running, fast!"}}}},"500":{"description":"Unexpected failure. Quote `error_reference` when reporting it","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}}}}},"/licenses/{reference}/products/{product_reference}":{"patch":{"tags":["Licenses"],"summary":"Change one product on a licence","description":"Administrators only. Add or replace models (`add_features`), remove them by name (`remove_features`), or change `max_users`, `valid_from` or `valid_to`. Anything not sent stays as it is, and the licence's other products are untouched. 409 if `max_users` is below the seats taken, which include invitations still holding one. `reference` is a licence, user or organisation reference. Answers with the whole licence after the change.","operationId":"amend_product_licenses__reference__products__product_reference__patch","parameters":[{"required":true,"schema":{"type":"string","title":"Reference"},"name":"reference","in":"path"},{"required":true,"schema":{"type":"string","title":"Product Reference"},"name":"product_reference","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"add_features":{"items":{"additionalProperties":true,"type":"object"},"type":"array","description":"Models to add, each with a `feature_name` and its boxes. One with the name of a model already held replaces it."},"remove_features":{"items":{"type":"string"},"type":"array","description":"Names of models to take away."},"max_users":{"type":"integer","description":"Seats. Not below the seats taken, which include invitations still holding one."},"valid_from":{"type":"string","description":"YYYY-MM-DD."},"valid_to":{"type":"string","description":"YYYY-MM-DD."}},"additionalProperties":true,"type":"object","title":"AmendProduct"},"example":{"add_features":[{"feature_name":"CS20","boxes":[{"lat_min":-35,"lat_max":-34,"lon_min":-59,"lon_max":-58,"coverage":0.20833,"bath_value":100}]}],"remove_features":["PATG"],"max_users":5,"valid_to":"2028-10-01"}}},"required":true},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"properties":{"reference":{"type":"string"},"user_reference":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"code":{"type":"string","nullable":true},"license_type":{"type":"string","nullable":true},"license_class":{"type":"string","nullable":true},"max_users":{"type":"integer","nullable":true},"duration":{"type":"integer","nullable":true},"valid_from":{"type":"string","nullable":true},"valid_to":{"type":"string","nullable":true},"entitlements":{"items":{"properties":{"product_reference":{"type":"string","nullable":true},"product_name":{"type":"string","nullable":true},"bundle_reference":{"type":"string","nullable":true},"bundle_name":{"type":"string","nullable":true},"license_type":{"type":"string","nullable":true},"license_class":{"type":"string","nullable":true},"max_users":{"type":"integer","nullable":true},"seats_used":{"type":"integer","description":"Seats taken: the people on it plus invitations still holding one. Show this, not the length of `users`."},"users":{"items":{"type":"string"},"type":"array"},"valid_from":{"type":"string","nullable":true},"valid_to":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"features":{"items":{"additionalProperties":true,"type":"object"},"type":"array"}},"additionalProperties":true,"type":"object","title":"Entitlement"},"type":"array"},"status":{"type":"string","nullable":true},"user_references":{"items":{"type":"string"},"type":"array"},"metadata":{"additionalProperties":true,"type":"object"},"created_by_reference":{"type":"string","nullable":true},"created_at_timestamp":{"type":"string","nullable":true},"updated_at_timestamp":{"type":"string","nullable":true},"expires_at_timestamp":{"type":"string","nullable":true},"expiry_reminders":{"additionalProperties":true,"type":"object"}},"additionalProperties":true,"type":"object","required":["reference"],"title":"LicenseRecord"},"example":{"reference":"11111111-1111-1111-1111-111111111111","user_reference":"22222222-2222-2222-2222-222222222222","email":"jane@example.com","code":"ABCD-EFGH-IJKL","license_type":"subscription","license_class":"professional","max_users":5,"duration":12,"valid_from":"2026-01-01","valid_to":"2027-01-01","entitlements":[{"product_reference":"prod-polpred","product_name":"PolPred","license_type":"subscription","license_class":"professional","max_users":5,"seats_used":1,"users":["22222222-2222-2222-2222-222222222222"],"valid_from":"2026-01-01","valid_to":"2027-01-01","status":"active","features":[{"feature_reference":"66666666-6666-6666-6666-666666666666","feature_name":"3D_CS20_7L","feature_type":"model","one_off":true,"prediction_window_start":"2026-01-01","prediction_window_end":"2026-12-31","hindcast_window_start":"2020-01-01","prediction_months":12,"boxes":[{"lat_min":50,"lat_max":52,"lon_min":-5,"lon_max":-3,"coverage":0.75}],"metadata":{"boundary":{"north":54,"south":50,"west":-5,"east":-3}}}]}],"status":"active","user_references":[],"metadata":{"organisation_reference":"55555555-5555-5555-5555-555555555555"},"created_at_timestamp":"2026-01-01T09:30:00","updated_at_timestamp":"2026-01-01T09:30:00","expires_at_timestamp":"2027-01-01T00:00:00","expiry_reminders":{"prod-polpred":{"valid_to":"2027-01-01","days_before":30}}}}}},"400":{"description":"A query parameter or the body is not usable, for example a latitude that is not a number","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"401":{"description":"No token, an expired token, not signed in, or not allowed to make this change","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"404":{"description":"No such licence, product or model, or a licence this caller is not on (the same answer, deliberately)","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"409":{"description":"The change conflicts with the licence, for example fewer seats than are in use","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"451":{"description":"The licence is expired or disabled","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"500":{"description":"Unexpected failure. Quote `error_reference` when reporting it","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/licenses/{reference}/products/{product_reference}/renew":{"post":{"tags":["Licenses"],"summary":"Renew an expired product","description":"Administrators only. Brings an expired product back to active, and the licence with it, keeping its members and models. `valid_to` is required and must be in the future; `valid_from` and `max_users` are optional and anything not sent stays as it is. A model keeps what was bought: one bought for part of the term has its end moved that many months past the renewal, a full-term one runs to `valid_to`, and a one-off stays where it is. 409 if the product has not expired, or `max_users` is below the seats taken, which include invitations still holding one; 451 if it is disabled. `reference` is a licence, user or organisation reference. Answers with the whole licence after the change.","operationId":"renew_product_licenses__reference__products__product_reference__renew_post","parameters":[{"required":true,"schema":{"type":"string","title":"Reference"},"name":"reference","in":"path"},{"required":true,"schema":{"type":"string","title":"Product Reference"},"name":"product_reference","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"properties":{"valid_to":{"type":"string","description":"YYYY-MM-DD, in the future."},"valid_from":{"type":"string","description":"YYYY-MM-DD. Stays as it is if not sent."},"max_users":{"type":"integer","description":"Seats. Not below the seats taken, which include invitations still holding one. Stays as it is if not sent."}},"additionalProperties":true,"type":"object","required":["valid_to"],"title":"RenewProduct"},"example":{"valid_from":"2026-11-05","valid_to":"2027-11-05","max_users":10}}},"required":true},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"properties":{"reference":{"type":"string"},"user_reference":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"code":{"type":"string","nullable":true},"license_type":{"type":"string","nullable":true},"license_class":{"type":"string","nullable":true},"max_users":{"type":"integer","nullable":true},"duration":{"type":"integer","nullable":true},"valid_from":{"type":"string","nullable":true},"valid_to":{"type":"string","nullable":true},"entitlements":{"items":{"properties":{"product_reference":{"type":"string","nullable":true},"product_name":{"type":"string","nullable":true},"bundle_reference":{"type":"string","nullable":true},"bundle_name":{"type":"string","nullable":true},"license_type":{"type":"string","nullable":true},"license_class":{"type":"string","nullable":true},"max_users":{"type":"integer","nullable":true},"seats_used":{"type":"integer","description":"Seats taken: the people on it plus invitations still holding one. Show this, not the length of `users`."},"users":{"items":{"type":"string"},"type":"array"},"valid_from":{"type":"string","nullable":true},"valid_to":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"features":{"items":{"additionalProperties":true,"type":"object"},"type":"array"}},"additionalProperties":true,"type":"object","title":"Entitlement"},"type":"array"},"status":{"type":"string","nullable":true},"user_references":{"items":{"type":"string"},"type":"array"},"metadata":{"additionalProperties":true,"type":"object"},"created_by_reference":{"type":"string","nullable":true},"created_at_timestamp":{"type":"string","nullable":true},"updated_at_timestamp":{"type":"string","nullable":true},"expires_at_timestamp":{"type":"string","nullable":true},"expiry_reminders":{"additionalProperties":true,"type":"object"}},"additionalProperties":true,"type":"object","required":["reference"],"title":"LicenseRecord"},"example":{"reference":"11111111-1111-1111-1111-111111111111","user_reference":"22222222-2222-2222-2222-222222222222","email":"jane@example.com","code":"ABCD-EFGH-IJKL","license_type":"subscription","license_class":"professional","max_users":5,"duration":12,"valid_from":"2026-01-01","valid_to":"2027-01-01","entitlements":[{"product_reference":"prod-polpred","product_name":"PolPred","license_type":"subscription","license_class":"professional","max_users":5,"seats_used":1,"users":["22222222-2222-2222-2222-222222222222"],"valid_from":"2026-01-01","valid_to":"2027-01-01","status":"active","features":[{"feature_reference":"66666666-6666-6666-6666-666666666666","feature_name":"3D_CS20_7L","feature_type":"model","one_off":true,"prediction_window_start":"2026-01-01","prediction_window_end":"2026-12-31","hindcast_window_start":"2020-01-01","prediction_months":12,"boxes":[{"lat_min":50,"lat_max":52,"lon_min":-5,"lon_max":-3,"coverage":0.75}],"metadata":{"boundary":{"north":54,"south":50,"west":-5,"east":-3}}}]}],"status":"active","user_references":[],"metadata":{"organisation_reference":"55555555-5555-5555-5555-555555555555"},"created_at_timestamp":"2026-01-01T09:30:00","updated_at_timestamp":"2026-01-01T09:30:00","expires_at_timestamp":"2027-01-01T00:00:00","expiry_reminders":{"prod-polpred":{"valid_to":"2027-01-01","days_before":30}}}}}},"400":{"description":"A query parameter or the body is not usable, for example a latitude that is not a number","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"401":{"description":"No token, an expired token, not signed in, or not allowed to make this change","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"404":{"description":"No such licence, product or model, or a licence this caller is not on (the same answer, deliberately)","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"409":{"description":"The change conflicts with the licence, for example fewer seats than are in use","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"451":{"description":"The licence is expired or disabled","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"500":{"description":"Unexpected failure. Quote `error_reference` when reporting it","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/licenses/{reference}/models":{"get":{"tags":["Licenses"],"summary":"Models a licence can be used with","description":"`reference` is a licence, user or organisation reference.\n\nWhich models the licence can be used with, filtered by place, dates and product.\n\nGeography and dates never remove a row: they set `available` and fill `reasons`. Add\n`available=true` for only the usable ones. Paged like every other listing: `page`\n(or `page=all`) and `ordering=field` / `ordering=-field`.","operationId":"search_models_licenses__reference__models_get","parameters":[{"required":true,"schema":{"type":"string","title":"Reference"},"name":"reference","in":"path"},{"description":"A point: latitude in degrees. Needs `longitude`.","required":false,"schema":{"type":"string","title":"Latitude","description":"A point: latitude in degrees. Needs `longitude`.","examples":["51.0"]},"name":"latitude","in":"query"},{"description":"A point: longitude in degrees. Needs `latitude`.","required":false,"schema":{"type":"string","title":"Longitude","description":"A point: longitude in degrees. Needs `latitude`.","examples":["-4.0"]},"name":"longitude","in":"query"},{"description":"An area: all four of north, south, east, west.","required":false,"schema":{"type":"string","title":"North","description":"An area: all four of north, south, east, west."},"name":"north","in":"query"},{"description":"An area: all four of north, south, east, west.","required":false,"schema":{"type":"string","title":"South","description":"An area: all four of north, south, east, west."},"name":"south","in":"query"},{"description":"An area: all four of north, south, east, west.","required":false,"schema":{"type":"string","title":"East","description":"An area: all four of north, south, east, west."},"name":"east","in":"query"},{"description":"An area: all four of north, south, east, west.","required":false,"schema":{"type":"string","title":"West","description":"An area: all four of north, south, east, west."},"name":"west","in":"query"},{"description":"Checked against each model's own window.","required":false,"schema":{"type":"string","title":"Start Date","description":"Checked against each model's own window.","examples":["2026-03-01"]},"name":"start_date","in":"query"},{"description":"Checked against each model's own window.","required":false,"schema":{"type":"string","title":"End Date","description":"Checked against each model's own window.","examples":["2026-04-01"]},"name":"end_date","in":"query"},{"description":"Exact match.","required":false,"schema":{"type":"string","title":"Product Reference","description":"Exact match."},"name":"product_reference","in":"query"},{"description":"Partial, case-insensitive.","required":false,"schema":{"type":"string","title":"Product Name","description":"Partial, case-insensitive."},"name":"product_name","in":"query"},{"description":"Partial, case-insensitive.","required":false,"schema":{"type":"string","title":"Model Code","description":"Partial, case-insensitive."},"name":"model_code","in":"query"},{"description":"Exact match, e.g. `model`.","required":false,"schema":{"type":"string","title":"Feature Type","description":"Exact match, e.g. `model`."},"name":"feature_type","in":"query"},{"description":"`true` for only the models that can run a 3D time series, `false` for only the others.","required":false,"schema":{"type":"string","title":"Multi Layer","description":"`true` for only the models that can run a 3D time series, `false` for only the others."},"name":"multi_layer","in":"query"},{"description":"Exact match, e.g. `active`.","required":false,"schema":{"type":"string","title":"Status","description":"Exact match, e.g. `active`."},"name":"status","in":"query"},{"description":"`true` to keep only models usable under the filters given.","required":false,"schema":{"type":"string","title":"Available","description":"`true` to keep only models usable under the filters given."},"name":"available","in":"query"},{"description":"Search across every field.","required":false,"schema":{"type":"string","title":"All","description":"Search across every field."},"name":"all","in":"query"},{"description":"Whose access to report; `all` for the whole licence. Anybody but yourself needs an admin role or licence ownership.","required":false,"schema":{"type":"string","title":"User Reference","description":"Whose access to report; `all` for the whole licence. Anybody but yourself needs an admin role or licence ownership."},"name":"user_reference","in":"query"},{"description":"Page number, or `all` for no paging.","required":false,"schema":{"type":"string","title":"Page","description":"Page number, or `all` for no paging.","examples":["1"]},"name":"page","in":"query"},{"description":"`field` ascending, `-field` descending. Default `model_code`.","required":false,"schema":{"type":"string","title":"Ordering","description":"`field` ascending, `-field` descending. Default `model_code`.","examples":["-valid_to"]},"name":"ordering","in":"query"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"properties":{"license_reference":{"type":"string"},"organisation_reference":{"type":"string","nullable":true},"user_reference":{"type":"string","nullable":true},"items":{"items":{"properties":{"model_code":{"type":"string"},"feature_reference":{"type":"string","nullable":true},"feature_type":{"type":"string","nullable":true},"product_reference":{"type":"string","nullable":true},"product_name":{"type":"string","nullable":true},"license_type":{"type":"string","nullable":true},"license_class":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"valid_from":{"type":"string","nullable":true},"valid_to":{"type":"string","nullable":true},"covers_from":{"type":"string","nullable":true},"covers_to":{"type":"string","nullable":true},"prediction_months":{"type":"integer","nullable":true},"one_off":{"type":"boolean","nullable":true},"boxes":{"type":"integer","nullable":true},"boxes_matched":{"type":"integer","nullable":true},"coverage":{"type":"number","nullable":true},"boundary":{"properties":{"north":{"type":"number"},"south":{"type":"number"},"west":{"type":"number"},"east":{"type":"number"}},"additionalProperties":true,"type":"object","title":"Boundary"},"multi_layer":{"type":"boolean"},"available":{"type":"boolean"},"reasons":{"items":{"type":"string"},"type":"array"}},"additionalProperties":true,"type":"object","required":["model_code","available","reasons"],"title":"ModelRow"},"type":"array"},"pagination":{"properties":{"current_page":{"type":"integer"},"page_size":{"type":"integer"},"total_records":{"type":"integer"},"total_pages":{"type":"integer"},"has_next":{"type":"boolean"},"has_previous":{"type":"boolean"}},"additionalProperties":true,"type":"object","title":"Pagination"}},"additionalProperties":true,"type":"object","required":["license_reference","items","pagination"],"title":"ModelSearch"},"example":{"license_reference":"11111111-1111-1111-1111-111111111111","organisation_reference":"55555555-5555-5555-5555-555555555555","user_reference":"22222222-2222-2222-2222-222222222222","items":[{"model_code":"3D_CS20_7L","feature_reference":"66666666-6666-6666-6666-666666666666","feature_type":"model","product_reference":"prod-polpred","product_name":"PolPred","license_type":"subscription","license_class":"professional","status":"active","valid_from":"2026-01-01","valid_to":"2027-01-01","covers_from":"2020-01-01","covers_to":"2026-12-31","prediction_months":12,"one_off":true,"boxes":2,"boxes_matched":1,"coverage":0.75,"boundary":{"north":54,"south":50,"west":-5,"east":-3},"multi_layer":true,"available":true,"reasons":[]},{"model_code":"CS3X_50HC","feature_reference":"66666666-6666-6666-6666-666666666666","feature_type":"model","product_reference":"prod-tidemorph","product_name":"TideMorph","license_type":"trial","license_class":"professional","status":"active","valid_from":"2026-01-01","valid_to":"2026-11-01","covers_from":"2020-01-01","covers_to":"2026-12-31","prediction_months":12,"one_off":true,"boxes":1,"boundary":{"north":60,"south":58,"west":0,"east":2},"multi_layer":false,"available":false,"reasons":["the point is outside the licensed area"]}],"pagination":{"current_page":1,"page_size":10,"total_records":2,"total_pages":1,"has_next":false,"has_previous":false}}}}},"400":{"description":"A query parameter or the body is not usable, for example a latitude that is not a number","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"401":{"description":"No token, an expired token, not signed in, or not allowed to make this change","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"404":{"description":"No such licence, product or model, or a licence this caller is not on (the same answer, deliberately)","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"500":{"description":"Unexpected failure. Quote `error_reference` when reporting it","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/licenses/{reference}/status":{"get":{"tags":["Licenses"],"summary":"Seats used per product","description":"For each product: status, dates, `max_users` and `seats_used`, which counts the people on it plus invitations still holding a seat. Only the owner, a seat holder or an administrator may read it.","operationId":"get_license_status_licenses__reference__status_get","parameters":[{"required":true,"schema":{"type":"string","title":"Reference"},"name":"reference","in":"path"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"properties":{"reference":{"type":"string"},"status":{"type":"string","nullable":true},"code":{"type":"string","nullable":true},"metadata":{"additionalProperties":true,"type":"object"},"created_at":{"type":"string","nullable":true},"expires_at":{"type":"string","nullable":true},"products":{"items":{"properties":{"product_reference":{"type":"string","nullable":true},"product_name":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"valid_from":{"type":"string","nullable":true},"valid_to":{"type":"string","nullable":true},"max_users":{"type":"integer","nullable":true},"seats_used":{"type":"integer"}},"additionalProperties":true,"type":"object","required":["seats_used"],"title":"StatusProduct"},"type":"array"}},"additionalProperties":true,"type":"object","required":["reference","products"],"title":"LicenseStatus"},"example":{"reference":"11111111-1111-1111-1111-111111111111","status":"active","code":"ABCD-EFGH-IJKL","metadata":{"organisation_reference":"55555555-5555-5555-5555-555555555555"},"created_at":"2026-01-01T09:30:00","expires_at":"2027-01-01T00:00:00","products":[{"product_reference":"prod-polpred","product_name":"PolPred","status":"active","valid_from":"2026-01-01","valid_to":"2027-01-01","max_users":5,"seats_used":1},{"product_reference":"prod-tidemorph","product_name":"TideMorph","status":"active","valid_from":"2026-01-01","valid_to":"2026-11-01","max_users":1,"seats_used":1}]}}}},"401":{"description":"No token, an expired token, not signed in, or not allowed to make this change","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"404":{"description":"No such licence, product or model, or a licence this caller is not on (the same answer, deliberately)","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"500":{"description":"Unexpected failure. Quote `error_reference` when reporting it","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/licenses/{reference}":{"get":{"tags":["Licenses"],"summary":"The full licence record","description":"`reference` is a licence reference or the reference of anybody on it. Read `entitlements`; the fields above them are a summary across live products. Show each entitlement's `seats_used`, which counts invitations still holding a seat, rather than the length of `users`. A caller not on the licence gets 404, the same as a reference that does not exist.","operationId":"get_license_by_reference_licenses__reference__get","parameters":[{"required":true,"schema":{"type":"string","title":"Reference"},"name":"reference","in":"path"}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"properties":{"reference":{"type":"string"},"user_reference":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"code":{"type":"string","nullable":true},"license_type":{"type":"string","nullable":true},"license_class":{"type":"string","nullable":true},"max_users":{"type":"integer","nullable":true},"duration":{"type":"integer","nullable":true},"valid_from":{"type":"string","nullable":true},"valid_to":{"type":"string","nullable":true},"entitlements":{"items":{"properties":{"product_reference":{"type":"string","nullable":true},"product_name":{"type":"string","nullable":true},"bundle_reference":{"type":"string","nullable":true},"bundle_name":{"type":"string","nullable":true},"license_type":{"type":"string","nullable":true},"license_class":{"type":"string","nullable":true},"max_users":{"type":"integer","nullable":true},"seats_used":{"type":"integer","description":"Seats taken: the people on it plus invitations still holding one. Show this, not the length of `users`."},"users":{"items":{"type":"string"},"type":"array"},"valid_from":{"type":"string","nullable":true},"valid_to":{"type":"string","nullable":true},"status":{"type":"string","nullable":true},"features":{"items":{"additionalProperties":true,"type":"object"},"type":"array"}},"additionalProperties":true,"type":"object","title":"Entitlement"},"type":"array"},"status":{"type":"string","nullable":true},"user_references":{"items":{"type":"string"},"type":"array"},"metadata":{"additionalProperties":true,"type":"object"},"created_by_reference":{"type":"string","nullable":true},"created_at_timestamp":{"type":"string","nullable":true},"updated_at_timestamp":{"type":"string","nullable":true},"expires_at_timestamp":{"type":"string","nullable":true},"expiry_reminders":{"additionalProperties":true,"type":"object"}},"additionalProperties":true,"type":"object","required":["reference"],"title":"LicenseRecord"},"example":{"reference":"11111111-1111-1111-1111-111111111111","user_reference":"22222222-2222-2222-2222-222222222222","email":"jane@example.com","code":"ABCD-EFGH-IJKL","license_type":"subscription","license_class":"professional","max_users":5,"duration":12,"valid_from":"2026-01-01","valid_to":"2027-01-01","entitlements":[{"product_reference":"prod-polpred","product_name":"PolPred","license_type":"subscription","license_class":"professional","max_users":5,"seats_used":1,"users":["22222222-2222-2222-2222-222222222222"],"valid_from":"2026-01-01","valid_to":"2027-01-01","status":"active","features":[{"feature_reference":"66666666-6666-6666-6666-666666666666","feature_name":"3D_CS20_7L","feature_type":"model","one_off":true,"prediction_window_start":"2026-01-01","prediction_window_end":"2026-12-31","hindcast_window_start":"2020-01-01","prediction_months":12,"boxes":[{"lat_min":50,"lat_max":52,"lon_min":-5,"lon_max":-3,"coverage":0.75}],"metadata":{"boundary":{"north":54,"south":50,"west":-5,"east":-3}}}]}],"status":"active","user_references":[],"metadata":{"organisation_reference":"55555555-5555-5555-5555-555555555555"},"created_at_timestamp":"2026-01-01T09:30:00","updated_at_timestamp":"2026-01-01T09:30:00","expires_at_timestamp":"2027-01-01T00:00:00","expiry_reminders":{"prod-polpred":{"valid_to":"2027-01-01","days_before":30}}}}}},"401":{"description":"No token, an expired token, not signed in, or not allowed to make this change","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"404":{"description":"No such licence, product or model, or a licence this caller is not on (the same answer, deliberately)","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"500":{"description":"Unexpected failure. Quote `error_reference` when reporting it","content":{"application/json":{"schema":{"properties":{"error_reference":{"type":"string"},"error_type":{"type":"string"},"errors":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},"status_code":{"type":"integer"},"timestamp":{"type":"string"}},"additionalProperties":true,"type":"object","required":["error_reference","error_type","errors","status_code","timestamp"],"title":"ErrorEnvelope"},"example":{"error_reference":"b7825cd3-59dc-43a9-9e1f-964676d3cf72","error_type":"NOT_FOUND_ERROR","errors":{"message":["License with reference 11111111-1111-1111-1111-111111111111 not found."]},"status_code":404,"timestamp":"2026-09-30T10:00:00.000000"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}}},"components":{"schemas":{"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"HTTPBearer":{"type":"http","description":"The access token from sign-in.","scheme":"bearer"}}}}