{"openapi":"3.1.0","info":{"title":"Hyyr Public API","version":"1.0.0","description":"Public API for the Hyyr procurement platform.\n\n## Authentication\nTwo methods are supported:\n- **OAuth 2.0 client credentials** (recommended): exchange your organization code and API key for a short-lived JWT via `POST /oauth/token`, then send it as `Authorization: Bearer <token>`. Discovery metadata is available at `/.well-known/oauth-authorization-server`.\n- **Static API key**: send the key directly as `Authorization: Bearer hyyr_…`.\n\nCreate a named API key and select its scopes under Innstillinger → Brukere og tilganger → API. Scopes apply across the organization.\nRead and write scopes are independent. Events and webhook scopes expose procurement and agreement activity. Webhook subscriptions continue until separately disabled or deleted.\n\n## Versioning\nAll resource endpoints are versioned under `/v1`. Backwards-incompatible changes are only introduced in a new version prefix; additive changes (new fields, new endpoints) may occur within a version. Unversioned paths (e.g. `/procurements`) are permanent aliases for `/v1` and remain supported."},"components":{"securitySchemes":{"Bearer":{"type":"http","scheme":"bearer","description":"API key generated in Hyyr settings (Innstillinger → API, format `hyyr_…`), or a JWT access token from `POST /oauth/token`."},"OAuth2":{"type":"oauth2","description":"OAuth 2.0 client credentials grant. client_id = your organization code, client_secret = your Hyyr API key.","flows":{"clientCredentials":{"tokenUrl":"/oauth/token","scopes":{"procurements:read":"Read organization procurements","procurements:write":"Create and update organization procurements and needs","agreements:read":"Read organization agreements","agreements:write":"Update organization agreements","events:read":"Read procurement and agreement activity, including metadata and performer details, across the organization","organization:read":"Read active organization members","webhooks:manage":"Manage all organization webhooks and receive procurement and agreement activity. Subscriptions continue until separately disabled or deleted."}}}}},"schemas":{"AgreementSupplier":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","description":"The name as written on the agreement."},"orgNumber":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"contactPersonName":{"type":"string","nullable":true},"supplier":{"$ref":"#/components/schemas/SupplierRegisterEntry"}},"required":["id","name","orgNumber","email","contactPersonName","supplier"]},"SupplierRegisterEntry":{"type":"object","nullable":true,"properties":{"id":{"type":"string","description":"The supplier register entry: one per company per buyer, shared by all its agreements."},"name":{"type":"string","description":"The register name: the supplier portal company name when linked, otherwise the name in the register."},"orgNumber":{"type":"string","nullable":true,"description":"Organization number without country prefix or separators."},"country":{"type":"string","nullable":true,"description":"ISO 3166-1 alpha-3, e.g. NOR. Null when unknown."}},"required":["id","name","orgNumber","country"],"description":"The supplier register entry for this row. Null only for rows not yet in the register."},"UpdateAgreementRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Agreement name"},"description":{"type":"string","nullable":true,"description":"Free-text description"},"maxValue":{"type":"integer","nullable":true,"description":"Maximum contract value"},"valueSpent":{"type":"integer","nullable":true,"description":"Value spent so far"},"contractId":{"type":"string","nullable":true,"description":"Case number (saksnummer)"},"startDate":{"type":"string","nullable":true,"format":"date-time","description":"Agreement start date (ISO 8601)"},"baseEndDate":{"type":"string","nullable":true,"format":"date-time","description":"Contractual end date before options; use this for explicit date corrections. On an ONGOING agreement this sets (or with null withdraws) the termination date; it cannot be sent together with a switch to ONGOING."},"endDate":{"type":"string","nullable":true,"format":"date-time","description":"Legacy end date: maximum for automatic renewal, current for manual renewal (ISO 8601)"},"durationAdditionalInformation":{"type":"string","nullable":true,"description":"Plain-text notes about the contract duration. Empty string clears the field."}}},"UpdateProcurementRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Title of the procurement"},"background":{"type":"string","description":"Description / background text"},"contractId":{"type":"string","nullable":true,"description":"Case number (saksnummer)"},"procedureDescription":{"type":"string","nullable":true,"description":"Custom override for the procedure description"}}},"CreateCompetitionExistingRequest":{"type":"object","properties":{"procurementId":{"type":"string","minLength":1,"description":"ID of the procurement"}},"required":["procurementId"]},"CreateCompetitionNewRequest":{"type":"object","properties":{"name":{"type":"string","description":"Title of the procurement"},"description":{"type":"string","description":"Short description"},"ownerUserId":{"type":"string","minLength":1,"description":"User ID of the owner (must belong to your organization)"},"lot":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"duration":{"type":"integer","minimum":0},"deadlineReceiptTenders":{"type":"string","format":"date-time"},"durationStart":{"type":"string","format":"date-time"},"durationEnd":{"type":"string","format":"date-time"},"estValue":{"type":"integer","nullable":true,"minimum":0},"awardCriteria":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","enum":["PRICE","COST","QUALITY","ENVIRONMENT"]},"weight":{"type":"integer","minimum":0,"maximum":100},"priceHandlingType":{"type":"string","enum":["TOTAL_PRICE","PRICE_SCHEMA"]}},"required":["name","description","type"]},"minItems":1}},"required":["description","duration","deadlineReceiptTenders","durationStart","durationEnd","awardCriteria"]}},"required":["name","description","ownerUserId","lot"]},"CreateMarketDialogExistingRequest":{"type":"object","properties":{"procurementId":{"type":"string","minLength":1,"description":"ID of the procurement"}},"required":["procurementId"]},"CreateMarketDialogNewRequest":{"type":"object","properties":{"name":{"type":"string","description":"Title of the procurement"},"description":{"type":"string","description":"Short description"},"ownerUserId":{"type":"string","minLength":1,"description":"User ID of the owner (must belong to your organization)"},"lot":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"duration":{"type":"integer","minimum":0},"deadlineReceiptTenders":{"type":"string","format":"date-time"},"durationStart":{"type":"string","format":"date-time"},"durationEnd":{"type":"string","format":"date-time"},"estValue":{"type":"integer","nullable":true,"minimum":0},"awardCriteria":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","enum":["PRICE","COST","QUALITY","ENVIRONMENT"]},"weight":{"type":"integer","minimum":0,"maximum":100},"priceHandlingType":{"type":"string","enum":["TOTAL_PRICE","PRICE_SCHEMA"]}},"required":["name","description","type"]},"minItems":1}},"required":["description","duration","deadlineReceiptTenders","durationStart","durationEnd","awardCriteria"]}},"required":["name","description","ownerUserId","lot"]}},"parameters":{}},"paths":{"/health":{"get":{"tags":["Health"],"summary":"Health check","responses":{"200":{"description":"API is healthy","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"}},"required":["status"]}}}}}}},"/oauth/token":{"post":{"tags":["OAuth"],"summary":"Issue an access token (client credentials)","description":"OAuth 2.0 client credentials grant (RFC 6749 §4.4). Exchange your organization code (`client_id`) and API key (`client_secret`) for a short-lived JWT access token. Client credentials may be sent in the form body or via HTTP Basic authentication.","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","description":"Must be `client_credentials`","example":"client_credentials"},"client_id":{"type":"string","description":"Your organization code. May alternatively be sent via HTTP Basic authentication."},"client_secret":{"type":"string","description":"Your Hyyr API key (`hyyr_…`). May alternatively be sent via HTTP Basic authentication."},"scope":{"type":"string","description":"Space-delimited scopes to request. Defaults to all scopes granted to the credential. Available scopes: procurements:read, procurements:write, agreements:read, agreements:write, events:read, organization:read, webhooks:manage","example":"procurements:read events:read"}},"required":["grant_type"]}}}},"responses":{"200":{"description":"Access token issued","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"expires_in":{"type":"integer"},"scope":{"type":"string"}},"required":["access_token","token_type","expires_in","scope"]}}}},"400":{"description":"Invalid request or scope","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"OAuth 2.0 error code (RFC 6749 §5.2): invalid_request, invalid_client, invalid_scope or unsupported_grant_type"},"error_description":{"type":"string"}},"required":["error"]}}}},"401":{"description":"Invalid client credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","description":"OAuth 2.0 error code (RFC 6749 §5.2): invalid_request, invalid_client, invalid_scope or unsupported_grant_type"},"error_description":{"type":"string"}},"required":["error"]}}}}}}},"/v1/agreements":{"get":{"tags":["Agreements"],"summary":"List all agreements for your organization","description":"Returns agreements for the authenticated organization. Each agreement includes its suppliers.","security":[{"Bearer":[]},{"OAuth2":["agreements:read"]}],"parameters":[{"schema":{"type":"string","enum":["FRAMEWORK_AGREEMENT","SIMPLE_AGREEMENT"],"description":"Filter by agreement type","example":"FRAMEWORK_AGREEMENT"},"required":false,"description":"Filter by agreement type","name":"type","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Number of results to return (1-100)"},"required":false,"description":"Number of results to return (1-100)","name":"limit","in":"query"},{"schema":{"type":"integer","nullable":true,"minimum":0,"default":0,"description":"Number of results to skip"},"required":false,"description":"Number of results to skip","name":"offset","in":"query"}],"responses":{"200":{"description":"List of agreements","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"type":{"type":"string","enum":["FRAMEWORK_AGREEMENT","SIMPLE_AGREEMENT"]},"maxValue":{"type":"integer","nullable":true},"valueSpent":{"type":"integer","nullable":true},"contractId":{"type":"string","nullable":true,"description":"Case number (saksnummer)"},"startDate":{"type":"string","nullable":true,"format":"date-time","description":"Stored agreement start date (ISO 8601 UTC); null when unknown"},"baseEndDate":{"type":"string","nullable":true,"format":"date-time","description":"Stored contractual end date before options (ISO 8601 UTC); for ONGOING agreements the termination date (null while not terminated). Null when unavailable. Reads do not infer a base from endDate."},"endDate":{"type":"string","nullable":true,"format":"date-time","description":"Stored legacy end date: maximum for automatic renewal, current for manual renewal (ISO 8601 UTC). Returned unchanged; not recalculated on reads."},"procurementId":{"type":"string","nullable":true},"lotId":{"type":"string","nullable":true},"durationAdditionalInformation":{"type":"string","nullable":true,"description":"Plain-text notes about the contract duration. Copied from the competition lot when the agreement is created from a procurement."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"contactPerson":{"type":"object","nullable":true,"properties":{"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true}},"required":["firstName","lastName","email","phone"]},"suppliers":{"type":"array","items":{"$ref":"#/components/schemas/AgreementSupplier"}}},"required":["id","name","description","type","maxValue","valueSpent","contractId","startDate","baseEndDate","endDate","procurementId","lotId","durationAdditionalInformation","createdAt","updatedAt","contactPerson","suppliers"]}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["total","limit","offset"]}},"required":["data","pagination"]}}}}}}},"/v1/agreements/{id}":{"get":{"tags":["Agreements"],"summary":"Get a single agreement by ID","security":[{"Bearer":[]},{"OAuth2":["agreements:read"]}],"parameters":[{"schema":{"type":"string","description":"Agreement ID"},"required":true,"description":"Agreement ID","name":"id","in":"path"}],"responses":{"200":{"description":"Agreement details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"type":{"type":"string","enum":["FRAMEWORK_AGREEMENT","SIMPLE_AGREEMENT"]},"maxValue":{"type":"integer","nullable":true},"valueSpent":{"type":"integer","nullable":true},"contractId":{"type":"string","nullable":true,"description":"Case number (saksnummer)"},"startDate":{"type":"string","nullable":true,"format":"date-time","description":"Stored agreement start date (ISO 8601 UTC); null when unknown"},"baseEndDate":{"type":"string","nullable":true,"format":"date-time","description":"Stored contractual end date before options (ISO 8601 UTC); for ONGOING agreements the termination date (null while not terminated). Null when unavailable. Reads do not infer a base from endDate."},"endDate":{"type":"string","nullable":true,"format":"date-time","description":"Stored legacy end date: maximum for automatic renewal, current for manual renewal (ISO 8601 UTC). Returned unchanged; not recalculated on reads."},"procurementId":{"type":"string","nullable":true},"lotId":{"type":"string","nullable":true},"durationAdditionalInformation":{"type":"string","nullable":true,"description":"Plain-text notes about the contract duration. Copied from the competition lot when the agreement is created from a procurement."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"contactPerson":{"type":"object","nullable":true,"properties":{"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true}},"required":["firstName","lastName","email","phone"]},"suppliers":{"type":"array","items":{"$ref":"#/components/schemas/AgreementSupplier"}}},"required":["id","name","description","type","maxValue","valueSpent","contractId","startDate","baseEndDate","endDate","procurementId","lotId","durationAdditionalInformation","createdAt","updatedAt","contactPerson","suppliers"]}},"required":["data"]}}}},"404":{"description":"Agreement not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}},"patch":{"tags":["Agreements"],"summary":"Update an agreement","description":"Partially updates an agreement. Only the provided fields are changed.","security":[{"Bearer":[]},{"OAuth2":["agreements:write"]}],"parameters":[{"schema":{"type":"string","description":"Agreement ID"},"required":true,"description":"Agreement ID","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAgreementRequest"}}}},"responses":{"200":{"description":"Updated agreement","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"type":{"type":"string","enum":["FRAMEWORK_AGREEMENT","SIMPLE_AGREEMENT"]},"maxValue":{"type":"integer","nullable":true},"valueSpent":{"type":"integer","nullable":true},"contractId":{"type":"string","nullable":true,"description":"Case number (saksnummer)"},"startDate":{"type":"string","nullable":true,"format":"date-time","description":"Stored agreement start date (ISO 8601 UTC); null when unknown"},"baseEndDate":{"type":"string","nullable":true,"format":"date-time","description":"Stored contractual end date before options (ISO 8601 UTC); for ONGOING agreements the termination date (null while not terminated). Null when unavailable. Reads do not infer a base from endDate."},"endDate":{"type":"string","nullable":true,"format":"date-time","description":"Stored legacy end date: maximum for automatic renewal, current for manual renewal (ISO 8601 UTC). Returned unchanged; not recalculated on reads."},"procurementId":{"type":"string","nullable":true},"lotId":{"type":"string","nullable":true},"durationAdditionalInformation":{"type":"string","nullable":true,"description":"Plain-text notes about the contract duration. Copied from the competition lot when the agreement is created from a procurement."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"contactPerson":{"type":"object","nullable":true,"properties":{"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true}},"required":["firstName","lastName","email","phone"]},"suppliers":{"type":"array","items":{"$ref":"#/components/schemas/AgreementSupplier"}}},"required":["id","name","description","type","maxValue","valueSpent","contractId","startDate","baseEndDate","endDate","procurementId","lotId","durationAdditionalInformation","createdAt","updatedAt","contactPerson","suppliers"]}},"required":["data"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Agreement not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/v1/events":{"get":{"tags":["Events"],"summary":"List activity events","description":"Returns a unified, newest-first feed of procurement and agreement activity for your organization. Poll with `since` (an ISO 8601 timestamp) to fetch only events created after your last check. For push-based delivery, register a webhook instead (see the Webhooks endpoints).","security":[{"Bearer":[]},{"OAuth2":["events:read"]}],"parameters":[{"schema":{"type":"string","format":"date-time","description":"Only return events created at or after this timestamp","example":"2026-01-01T00:00:00.000Z"},"required":false,"description":"Only return events created at or after this timestamp","name":"since","in":"query"},{"schema":{"type":"string","enum":["procurement","agreement"],"description":"Filter by resource type","example":"procurement"},"required":false,"description":"Filter by resource type","name":"type","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Number of results to return (1-100)"},"required":false,"description":"Number of results to return (1-100)","name":"limit","in":"query"},{"schema":{"type":"integer","nullable":true,"minimum":0,"default":0,"description":"Number of results to skip"},"required":false,"description":"Number of results to skip","name":"offset","in":"query"}],"responses":{"200":{"description":"List of activity events","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Audit log entry ID"},"type":{"type":"string","enum":["procurement","agreement"],"description":"Which resource the event relates to"},"resourceId":{"type":"string","description":"ID of the procurement or agreement the event relates to"},"action":{"type":"string","description":"Machine-readable action code"},"description":{"type":"string","description":"Human-readable description of the event"},"metadata":{"type":"object","nullable":true,"additionalProperties":{"nullable":true},"description":"Structured details about the change"},"performedBy":{"type":"object","nullable":true,"properties":{"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true}},"required":["firstName","lastName","email"],"description":"User who performed the action, if known"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","type","resourceId","action","description","metadata","performedBy","createdAt"]}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["total","limit","offset"]}},"required":["data","pagination"]}}}}}}},"/v1/organization/members":{"get":{"tags":["Organization"],"summary":"Get all members in your organization","description":"Returns all users that belong to the organization (tenant) associated with your API key.","security":[{"Bearer":[]},{"OAuth2":["organization:read"]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Number of results to return (1-100)"},"required":false,"description":"Number of results to return (1-100)","name":"limit","in":"query"},{"schema":{"type":"integer","nullable":true,"minimum":0,"default":0,"description":"Number of results to skip"},"required":false,"description":"Number of results to skip","name":"offset","in":"query"}],"responses":{"200":{"description":"List of organization members","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"User ID"},"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string","nullable":true},"title":{"type":"string","nullable":true},"department":{"type":"string","nullable":true},"roles":{"type":"array","items":{"type":"string","enum":["ADMIN","REQUESTOR","PURCHASER"]}},"joinedAt":{"type":"string","format":"date-time"}},"required":["id","firstName","lastName","email","phone","title","department","roles","joinedAt"]}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["total","limit","offset"]}},"required":["data","pagination"]}}}},"404":{"description":"Organization not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/v1/procurements/active":{"get":{"tags":["Procurements"],"summary":"List active procurements","description":"Returns procurements that are published and open for tenders. Filtered to status \"published\".","security":[{"Bearer":[]},{"OAuth2":["procurements:read"]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Number of results to return (1-100)"},"required":false,"description":"Number of results to return (1-100)","name":"limit","in":"query"},{"schema":{"type":"integer","nullable":true,"minimum":0,"default":0,"description":"Number of results to skip"},"required":false,"description":"Number of results to skip","name":"offset","in":"query"}],"responses":{"200":{"description":"List of active procurements","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["draft","published","closed","cancelled"]},"procedureType":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"lots":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","nullable":true},"description":{"type":"string"},"estValue":{"type":"number","nullable":true},"deadlineReceiptTenders":{"type":"string","format":"date-time"},"durationStart":{"type":"string","format":"date-time"},"durationEnd":{"type":"string","format":"date-time"},"cpvCodes":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"description":{"type":"string"},"isMain":{"type":"boolean"}},"required":["code","description","isMain"]}}},"required":["id","name","description","estValue","deadlineReceiptTenders","durationStart","durationEnd","cpvCodes"]}},"contactPerson":{"type":"object","nullable":true,"properties":{"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true}},"required":["firstName","lastName","email","phone"]}},"required":["id","name","status","procedureType","createdAt","updatedAt","lots","contactPerson"]}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["total","limit","offset"]}},"required":["data","pagination"]}}}}}}},"/v1/procurements":{"get":{"tags":["Procurements"],"summary":"List procurements","description":"Returns procurements for your organization. Optionally filter by status (draft, published, closed, cancelled).","security":[{"Bearer":[]},{"OAuth2":["procurements:read"]}],"parameters":[{"schema":{"type":"string","enum":["draft","published","closed","cancelled"],"description":"Filter by status","example":"published"},"required":false,"description":"Filter by status","name":"status","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"description":"Number of results to return (1-100)"},"required":false,"description":"Number of results to return (1-100)","name":"limit","in":"query"},{"schema":{"type":"integer","nullable":true,"minimum":0,"default":0,"description":"Number of results to skip"},"required":false,"description":"Number of results to skip","name":"offset","in":"query"}],"responses":{"200":{"description":"List of procurements","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["draft","published","closed","cancelled"]},"procedureType":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"lots":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","nullable":true},"description":{"type":"string"},"estValue":{"type":"number","nullable":true},"deadlineReceiptTenders":{"type":"string","format":"date-time"},"durationStart":{"type":"string","format":"date-time"},"durationEnd":{"type":"string","format":"date-time"},"cpvCodes":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"description":{"type":"string"},"isMain":{"type":"boolean"}},"required":["code","description","isMain"]}}},"required":["id","name","description","estValue","deadlineReceiptTenders","durationStart","durationEnd","cpvCodes"]}},"contactPerson":{"type":"object","nullable":true,"properties":{"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true}},"required":["firstName","lastName","email","phone"]}},"required":["id","name","status","procedureType","createdAt","updatedAt","lots","contactPerson"]}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["total","limit","offset"]}},"required":["data","pagination"]}}}}}}},"/v1/procurements/:id":{"get":{"tags":["Procurements"],"summary":"Get one procurement","description":"Returns a single procurement by ID, including lots and contact person.","security":[{"Bearer":[]},{"OAuth2":["procurements:read"]}],"parameters":[{"schema":{"type":"string","description":"Procurement ID"},"required":true,"description":"Procurement ID","name":"id","in":"path"}],"responses":{"200":{"description":"Procurement details","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["draft","published","closed","cancelled"]},"procedureType":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"lots":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","nullable":true},"description":{"type":"string"},"estValue":{"type":"number","nullable":true},"deadlineReceiptTenders":{"type":"string","format":"date-time"},"durationStart":{"type":"string","format":"date-time"},"durationEnd":{"type":"string","format":"date-time"},"cpvCodes":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"description":{"type":"string"},"isMain":{"type":"boolean"}},"required":["code","description","isMain"]}}},"required":["id","name","description","estValue","deadlineReceiptTenders","durationStart","durationEnd","cpvCodes"]}},"contactPerson":{"type":"object","nullable":true,"properties":{"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true}},"required":["firstName","lastName","email","phone"]}},"required":["id","name","status","procedureType","createdAt","updatedAt","lots","contactPerson"]}},"required":["data"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}},"patch":{"tags":["Procurements"],"summary":"Update a procurement","description":"Partially updates a procurement. Only the provided fields are changed.","security":[{"Bearer":[]},{"OAuth2":["procurements:write"]}],"parameters":[{"schema":{"type":"string","description":"Procurement ID"},"required":true,"description":"Procurement ID","name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProcurementRequest"}}}},"responses":{"200":{"description":"Updated procurement","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["draft","published","closed","cancelled"]},"procedureType":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"lots":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","nullable":true},"description":{"type":"string"},"estValue":{"type":"number","nullable":true},"deadlineReceiptTenders":{"type":"string","format":"date-time"},"durationStart":{"type":"string","format":"date-time"},"durationEnd":{"type":"string","format":"date-time"},"cpvCodes":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"description":{"type":"string"},"isMain":{"type":"boolean"}},"required":["code","description","isMain"]}}},"required":["id","name","description","estValue","deadlineReceiptTenders","durationStart","durationEnd","cpvCodes"]}},"contactPerson":{"type":"object","nullable":true,"properties":{"firstName":{"type":"string","nullable":true},"lastName":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"phone":{"type":"string","nullable":true}},"required":["firstName","lastName","email","phone"]}},"required":["id","name","status","procedureType","createdAt","updatedAt","lots","contactPerson"]}},"required":["data"]}}}},"400":{"description":"Invalid input","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/v1/procurements/rfp":{"post":{"tags":["Procurements"],"summary":"Create a need (behov)","description":"Creates a new need (behov). Send a short description and the user who will own it. Returns the new need ID. Legacy path `/rfp` is retained for compatibility.","security":[{"Bearer":[]},{"OAuth2":["procurements:write"]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string"},"ownerUserId":{"type":"string","minLength":1}},"required":["description","ownerUserId"]}}}},"responses":{"201":{"description":"RFP created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"]}},"required":["data"]}}}},"400":{"description":"Invalid input or owner user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"403":{"description":"Tenant not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/v1/procurements/competitions":{"post":{"tags":["Procurements"],"summary":"Create a competition","description":"Either start a competition for an existing procurement (send procurementId) or create a new procurement and competition (send name, description, owner, and a simplified lot with description, dates, and award criteria).","security":[{"Bearer":[]},{"OAuth2":["procurements:write"]}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CreateCompetitionExistingRequest"},{"$ref":"#/components/schemas/CreateCompetitionNewRequest"}]}}}},"responses":{"201":{"description":"Competition created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]}},"required":["data"]}}}},"400":{"description":"Invalid input or owner user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"403":{"description":"Tenant not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Procurement not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/v1/procurements/market-dialogs":{"post":{"tags":["Procurements"],"summary":"Create a market dialogue","description":"Either add a market dialogue to an existing procurement (send procurementId) or create a new procurement and market dialogue (send name, description, owner, and a simplified lot with description, dates, and award criteria).","security":[{"Bearer":[]},{"OAuth2":["procurements:write"]}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CreateMarketDialogExistingRequest"},{"$ref":"#/components/schemas/CreateMarketDialogNewRequest"}]}}}},"responses":{"201":{"description":"Market dialogue created","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"procurementId":{"type":"string"},"marketDialogId":{"type":"string"}},"required":["procurementId","marketDialogId"]}},"required":["data"]}}}},"400":{"description":"Invalid input or owner user","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"403":{"description":"Tenant not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Procurement not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/v1/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhooks","description":"Returns all webhook subscriptions for your organization. Deliveries are POST requests containing new activity events, signed with HMAC-SHA256 (X-Hyyr-Signature header).","security":[{"Bearer":[]},{"OAuth2":["webhooks:manage"]}],"responses":{"200":{"description":"List of webhooks","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Webhook ID"},"url":{"type":"string","description":"Delivery URL (HTTPS)"},"eventTypes":{"type":"array","items":{"type":"string","enum":["procurement","agreement"]},"description":"Event types delivered to this webhook. Empty array = all."},"active":{"type":"boolean","description":"Whether deliveries are enabled. Webhooks are disabled automatically after repeated delivery failures."},"failureCount":{"type":"integer","description":"Consecutive failed delivery attempts"},"lastSuccessAt":{"type":"string","nullable":true,"format":"date-time"},"lastFailureAt":{"type":"string","nullable":true,"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","url","eventTypes","active","failureCount","lastSuccessAt","lastFailureAt","createdAt"]}}},"required":["data"]}}}}}},"post":{"tags":["Webhooks"],"summary":"Create a webhook","description":"Registers an HTTPS endpoint that receives activity events as they happen, without polling. The response includes the signing `secret` exactly once. Verify deliveries by computing HMAC-SHA256 of the raw request body with the secret and comparing it to the X-Hyyr-Signature header (`sha256=<hex>`).","security":[{"Bearer":[]},{"OAuth2":["webhooks:manage"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"format":"uri","description":"HTTPS endpoint that receives event deliveries as POST requests","example":"https://example.com/hooks/hyyr"},"eventTypes":{"type":"array","items":{"type":"string","enum":["procurement","agreement"]},"description":"Event types to deliver. Omit for all types."}},"required":["url"]}}}},"responses":{"201":{"description":"Webhook created. The secret is only returned here.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Webhook ID"},"url":{"type":"string","description":"Delivery URL (HTTPS)"},"eventTypes":{"type":"array","items":{"type":"string","enum":["procurement","agreement"]},"description":"Event types delivered to this webhook. Empty array = all."},"active":{"type":"boolean","description":"Whether deliveries are enabled. Webhooks are disabled automatically after repeated delivery failures."},"failureCount":{"type":"integer","description":"Consecutive failed delivery attempts"},"lastSuccessAt":{"type":"string","nullable":true,"format":"date-time"},"lastFailureAt":{"type":"string","nullable":true,"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"secret":{"type":"string","description":"Signing secret for verifying deliveries (HMAC-SHA256 of the request body, sent in the X-Hyyr-Signature header). Only returned on creation — store it securely."}},"required":["id","url","eventTypes","active","failureCount","lastSuccessAt","lastFailureAt","createdAt","secret"]}}}},"400":{"description":"Invalid URL or webhook limit reached","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}},"/v1/webhooks/{id}":{"patch":{"tags":["Webhooks"],"summary":"Update a webhook","description":"Updates the URL, event type filter, or active state of a webhook. Use `active: true` to re-enable a webhook that was disabled after repeated delivery failures.","security":[{"Bearer":[]},{"OAuth2":["webhooks:manage"]}],"parameters":[{"schema":{"type":"string","description":"Webhook ID"},"required":true,"description":"Webhook ID","name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","maxLength":2000,"format":"uri"},"eventTypes":{"type":"array","items":{"type":"string","enum":["procurement","agreement"]}},"active":{"type":"boolean","description":"Set to true to re-enable a webhook disabled after failures"}}}}}},"responses":{"200":{"description":"Updated webhook","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Webhook ID"},"url":{"type":"string","description":"Delivery URL (HTTPS)"},"eventTypes":{"type":"array","items":{"type":"string","enum":["procurement","agreement"]},"description":"Event types delivered to this webhook. Empty array = all."},"active":{"type":"boolean","description":"Whether deliveries are enabled. Webhooks are disabled automatically after repeated delivery failures."},"failureCount":{"type":"integer","description":"Consecutive failed delivery attempts"},"lastSuccessAt":{"type":"string","nullable":true,"format":"date-time"},"lastFailureAt":{"type":"string","nullable":true,"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","url","eventTypes","active","failureCount","lastSuccessAt","lastFailureAt","createdAt"]}}}},"400":{"description":"Invalid URL","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}},"delete":{"tags":["Webhooks"],"summary":"Delete a webhook","security":[{"Bearer":[]},{"OAuth2":["webhooks:manage"]}],"parameters":[{"schema":{"type":"string","description":"Webhook ID"},"required":true,"description":"Webhook ID","name":"id","in":"path"}],"responses":{"204":{"description":"Webhook deleted"},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]}}}}}}}}}