openapi: 3.0.2 info: version: 1.7.0 title: Yagna Market API description: ' ## Yagna Market The Yagna Market is a core component of the Yagna Network, which enables computational Offers and Demands circulation. The Market is open for all entities willing to buy computations (Demands) or monetize computational resources (Offers). ## Yagna Market API The Yagna Market API is the entry to the Yagna Market through which Requestors and Providers can publish their Demands and Offers respectively, find matching counterparty, conduct negotiations and make an agreement. This version of Market API conforms with capability level 1 of the Market API specification. Market API contains two roles: Requestors and Providers which are symmetrical most of the time (excluding agreement phase). ' servers: - url: /market-api/v1 security: - app_key: [ ] tags: - name: requestor description: Requestor part - name: provider description: Provider part paths: /scan: post: tags: - requestor description: > Creates new offer/demand Iterator. operationId: beginScan requestBody: $ref: '#/components/requestBodies/NewScan' responses: 201: $ref: '#/components/responses/ScanId' 400: $ref: 'common.yaml#/responses/BadRequest' 401: $ref: 'common.yaml#/responses/Unauthorized' default: $ref: 'common.yaml#/responses/UnexpectedError' /scan/{subscriptionId}/events: get: tags: - requestor operationId: collectScanResults parameters: - $ref: '#/components/parameters/subscriptionId' - $ref: 'common.yaml#/parameters/pollTimeout' - $ref: 'common.yaml#/parameters/maxEvents' - $ref: '#/components/parameters/eventPeerId' responses: 200: $ref: '#/components/responses/ScanEvents' 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' default: $ref: 'common.yaml#/responses/UnexpectedError' delete: tags: - requestor operationId: endScan parameters: - $ref: '#/components/parameters/subscriptionId' responses: 201: description: scan deleted 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' default: $ref: 'common.yaml#/responses/UnexpectedError' /offers: get: tags: - provider operationId: getOffers summary: GetOffers - Fetches all active Offers which have been published by the Provider. responses: 200: $ref: '#/components/responses/OfferList' 400: $ref: 'common.yaml#/responses/BadRequest' 401: $ref: 'common.yaml#/responses/Unauthorized' default: $ref: 'common.yaml#/responses/UnexpectedError' post: tags: - provider operationId: subscribeOffer summary: SubscribeOffer - Publishes Provider capabilities via Offer. description: > Offer object can be considered an "open" or public Offer, as it is not directed at a specific Requestor, but rather is sent to the market so that the matching mechanism implementation can associate relevant Demands. **Note**: it is an "atomic" operation, ie. as soon as Subscription is placed, the Offer is published on the market. requestBody: $ref: '#/components/requestBodies/Offer' responses: 201: $ref: '#/components/responses/SubscriptionId' 400: $ref: 'common.yaml#/responses/BadRequest' 401: $ref: 'common.yaml#/responses/Unauthorized' default: $ref: 'common.yaml#/responses/UnexpectedError' /offers/{subscriptionId}: parameters: - $ref: '#/components/parameters/subscriptionId' delete: tags: - provider operationId: unsubscribeOffer summary: UnsubscribeOffer - Stop subscription for previously published Offer. description: > Stop receiving Proposals. **Note**: this will terminate all pending `collectDemands` calls on this subscription. This implies, that client code should not `unsubscribeOffer` before it has received all expected/useful inputs from `collectDemands`. responses: 204: description: Offer revoked. 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 410: description: Already unsubscribed. default: $ref: 'common.yaml#/responses/UnexpectedError' /offers/{subscriptionId}/events: parameters: - $ref: '#/components/parameters/subscriptionId' - $ref: 'common.yaml#/parameters/pollTimeout' - $ref: 'common.yaml#/parameters/maxEvents' get: tags: - provider operationId: collectDemands summary: CollectDemands - Reads Market responses to published Offer. description: > This is a blocking operation. It will not return until there is at least one new event. Returns Proposal related events: * `ProposalEvent` - Indicates that there is new Demand Proposal for this Offer. * `ProposalRejectedEvent` - Indicates that the Requestor has rejected our previous Proposal related to this Offer. This effectively ends a Negotiation chain - it explicitly indicates that the sender will not create another counter-Proposal. * `AgreementEvent` - Indicates that the Requestor is accepting our previous Proposal and ask for our approval of the Agreement. * `PropertyQueryEvent` - not supported yet. **Note**: When `collectDemands` is waiting, simultaneous call to `unsubscribeOffer` on the same `subscriptionId` should result in "Subscription does not exist" error returned from `collectDemands`. **Note**: Specification requires this endpoint to support list of specific Proposal Ids to listen for messages related only to specific Proposals. This is not covered yet. responses: 200: $ref: '#/components/responses/EventList' 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' default: $ref: 'common.yaml#/responses/UnexpectedError' /offers/{subscriptionId}/propertyQuery/{queryId}: parameters: - $ref: '#/components/parameters/subscriptionId' - $ref: '#/components/parameters/queryId' post: tags: - provider operationId: queryReplyOffers summary: QueryReplyOffers - Handles dynamic property query. description: > Sends a response to a received property value query. The Market Matching Mechanism, when resolving the match relation for the specific Demand-Offer pair, is to detect the “dynamic” properties required (via constraints) by the other side. At this point, it is able to query the issuing node for those properties and submit the other side’s requested properties as the context of the query. **Note**: The property query responses may be submitted in “chunks”, ie. the responder may choose to resolve ‘quick’/lightweight’ properties faster and provide response sooner, while still working on more time-consuming properties in the background. Therefore the response contains both the resolved properties, as well as list of properties which responder knows still require resolution. **Note**: This method must be implemented for Market API Capability Level 2. requestBody: $ref: '#/components/requestBodies/PropertyQueryReply' responses: 204: description: OK, query reply posted. 400: $ref: 'common.yaml#/responses/BadRequest' 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' default: $ref: 'common.yaml#/responses/UnexpectedError' /offers/{subscriptionId}/proposals/{proposalId}: parameters: - $ref: '#/components/parameters/subscriptionId' - $ref: '#/components/parameters/proposalId' get: tags: - provider operationId: getProposalDemand summary: GetProposalDemand - Fetches Proposal (Demand) with given id. responses: 200: $ref: '#/components/responses/Proposal' 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 410: description: Proposal rejected. default: $ref: 'common.yaml#/responses/UnexpectedError' post: tags: - provider operationId: counterProposalOffer summary: CounterProposalOffer - Responds with a bespoke Offer to received Demand. description: > Creates and sends a modified version of original Offer (a counter-proposal) adjusted to previously received Proposal (ie. Demand). Changes Proposal state to `Draft`. Returns created Proposal id. requestBody: $ref: '#/components/requestBodies/Proposal' responses: 201: $ref: '#/components/responses/ProposalId' 400: $ref: 'common.yaml#/responses/BadRequest' 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 410: description: Proposal rejected. default: $ref: 'common.yaml#/responses/UnexpectedError' /offers/{subscriptionId}/proposals/{proposalId}/reject: parameters: - $ref: '#/components/parameters/subscriptionId' - $ref: '#/components/parameters/proposalId' post: tags: - provider operationId: rejectProposalDemand summary: RejectProposalDemand - Rejects Proposal (Demand). description: > Effectively ends a Negotiation chain - it explicitly indicates that the sender will not create another counter-Proposal. requestBody: $ref: '#/components/requestBodies/Reason' responses: 204: description: Proposal rejected. 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 410: description: Proposal already rejected. default: $ref: 'common.yaml#/responses/UnexpectedError' /demands: get: tags: - requestor operationId: getDemands summary: GetDemands - Fetches all active Demands which have been published by the Requestor. responses: 200: $ref: '#/components/responses/DemandList' 400: $ref: 'common.yaml#/responses/BadRequest' 401: $ref: 'common.yaml#/responses/Unauthorized' default: $ref: 'common.yaml#/responses/UnexpectedError' post: tags: - requestor operationId: subscribeDemand summary: SubscribeDemand - Publishes Requestor capabilities via Demand. description: > Demand object can be considered an "open" or public Demand, as it is not directed at a specific Provider, but rather is sent to the market so that the matching mechanism implementation can associate relevant Offers. **Note**: it is an "atomic" operation, ie. as soon as Subscription is placed, the Demand is published on the market. requestBody: $ref: '#/components/requestBodies/Demand' responses: 201: $ref: '#/components/responses/SubscriptionId' 400: $ref: 'common.yaml#/responses/BadRequest' 401: $ref: 'common.yaml#/responses/Unauthorized' default: $ref: 'common.yaml#/responses/UnexpectedError' /demands/{subscriptionId}: parameters: - $ref: '#/components/parameters/subscriptionId' delete: tags: - requestor operationId: unsubscribeDemand summary: UnsubscribeDemand - Stop subscription for previously published Demand. description: > Stop receiving Proposals. **Note**: this will terminate all pending `collectOffers` calls on this subscription. This implies, that client code should not `unsubscribeDemand` before it has received all expected/useful inputs from `collectOffers`. responses: 204: description: Demand revoked. 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 410: description: Already unsubscribed. default: $ref: 'common.yaml#/responses/UnexpectedError' /demands/{subscriptionId}/events: parameters: - $ref: '#/components/parameters/subscriptionId' - $ref: 'common.yaml#/parameters/pollTimeout' - $ref: 'common.yaml#/parameters/maxEvents' get: tags: - requestor operationId: collectOffers summary: CollectOffers - Reads Market responses to published Demand. description: > This is a blocking operation. It will not return until there is at least one new event. Returns Proposal related events: * `ProposalEvent` - Indicates that there is new Offer Proposal for this Demand. * `ProposalRejectedEvent` - Indicates that the Provider has rejected our previous Proposal related to this Demand. This effectively ends a Negotiation chain - it explicitly indicates that the sender will not create another counter-Proposal. * `PropertyQueryEvent` - not supported yet. **Note**: When `collectOffers` is waiting, simultaneous call to `unsubscribeDemand` on the same `subscriptionId` should result in "Subscription does not exist" error returned from `collectOffers`. **Note**: Specification requires this endpoint to support list of specific Proposal Ids to listen for messages related only to specific Proposals. This is not covered yet. responses: 200: $ref: '#/components/responses/EventList' 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' default: $ref: 'common.yaml#/responses/UnexpectedError' /demands/{subscriptionId}/propertyQuery/{queryId}: parameters: - $ref: '#/components/parameters/subscriptionId' - $ref: '#/components/parameters/queryId' post: tags: - requestor operationId: queryReplyDemands summary: QueryReplyDemands - Handles dynamic property query. description: > Sends a response to a received property value query. The Market Matching Mechanism, when resolving the match relation for the specific Demand-Offer pair, is to detect the “dynamic” properties required (via constraints) by the other side. At this point, it is able to query the issuing node for those properties and submit the other side’s requested properties as the context of the query. **Note**: The property query responses may be submitted in “chunks”, ie. the responder may choose to resolve ‘quick’/lightweight’ properties faster and provide response sooner, while still working on more time-consuming properties in the background. Therefore the response contains both the resolved properties, as well as list of properties which responder knows still require resolution. **Note**: This method must be implemented for Market API Capability Level 2. requestBody: $ref: '#/components/requestBodies/PropertyQueryReply' responses: 204: description: OK, query reply posted. 400: $ref: 'common.yaml#/responses/BadRequest' 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' default: $ref: 'common.yaml#/responses/UnexpectedError' /demands/{subscriptionId}/proposals/{proposalId}: parameters: - $ref: '#/components/parameters/subscriptionId' - $ref: '#/components/parameters/proposalId' get: tags: - requestor operationId: getProposalOffer summary: GetProposalOffer - Fetches Proposal (Offer) with given id. responses: 200: $ref: '#/components/responses/Proposal' 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 410: description: Proposal rejected. default: $ref: 'common.yaml#/responses/UnexpectedError' post: tags: - requestor operationId: counterProposalDemand summary: CounterProposalDemand - Responds with a bespoke Demand to received Offer. description: > Creates and sends a modified version of original Demand (a counter-proposal) adjusted to previously received Proposal (ie. Offer). Changes Proposal state to `Draft`. Returns created Proposal id. requestBody: $ref: '#/components/requestBodies/Proposal' responses: 201: $ref: '#/components/responses/ProposalId' 400: $ref: 'common.yaml#/responses/BadRequest' 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 410: description: Proposal rejected. default: $ref: 'common.yaml#/responses/UnexpectedError' /demands/{subscriptionId}/proposals/{proposalId}/reject: parameters: - $ref: '#/components/parameters/subscriptionId' - $ref: '#/components/parameters/proposalId' post: tags: - requestor operationId: rejectProposalOffer summary: RejectProposalOffer - Rejects Proposal (Offer). description: > Effectively ends a Negotiation chain - it explicitly indicates that the sender will not create another counter-Proposal. requestBody: $ref: '#/components/requestBodies/Reason' responses: 204: description: Proposal rejected. 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 410: description: Proposal already rejected. default: $ref: 'common.yaml#/responses/UnexpectedError' /agreements: get: parameters: - $ref: 'common.yaml#/parameters/appSessionId' - name: state description: State of an agreement required: false in: query schema: $ref: '#/components/schemas/AgreementState' - $ref: 'common.yaml#/parameters/afterTimestamp' name: afterDate - $ref: 'common.yaml#/parameters/beforeTimestamp' name: beforeDate tags: - requestor - provider operationId: listAgreements summary: ListAgreements - Lists agreements with optional filters description: > List agreements. Supported filters: * state * creation datetime * app session id A well-formed call will result in a collection of objects with the following fields: * id * creationTs * approveTs * role responses: 200: $ref: '#/components/responses/AgreementList' 400: $ref: 'common.yaml#/responses/BadRequest' 401: $ref: 'common.yaml#/responses/Unauthorized' default: $ref: 'common.yaml#/responses/UnexpectedError' post: tags: - requestor operationId: createAgreement summary: CreateAgreement - Creates Agreement from selected Proposal. description: > Initiates the Agreement handshake phase. Formulates an Agreement artifact from the Proposal indicated by the received Proposal Id. Created Agreement is in `Proposal` state. The Approval Expiry Date is added to Agreement artifact and implies the effective timeout on the whole Agreement Confirmation sequence. A successful call to `createAgreement` shall immediately be followed by a `confirmAgreement` and `waitForApproval` call in order to listen for responses from the Provider. **Note**: Moves given Proposal to `Approved` state. requestBody: $ref: '#/components/requestBodies/AgreementProposal' responses: 201: description: Agreement created. content: application/json: schema: type: string description: Agreement Id links: GetAgreementById: description: The response value can be used to fetch Agreement in `GET /agreements/{agreementId}` operationId: getAgreement #operationRef: '#/paths/~1agreements~1{agreementId}/get' parameters: agreementId: '$response.body' 400: $ref: 'common.yaml#/responses/BadRequest' 401: $ref: 'common.yaml#/responses/Unauthorized' 409: $ref: 'common.yaml#/responses/Conflict' description: Proposal not negotiated yet (in `Initial` state). 410: $ref: 'common.yaml#/responses/Gone' description: Proposal rejected or expired. default: $ref: 'common.yaml#/responses/UnexpectedError' /agreements/{agreementId}: parameters: - $ref: '#/components/parameters/agreementId' get: tags: - requestor - provider operationId: getAgreement summary: GetAgreement - Fetches agreement with given agreement id. responses: 200: description: Agreement. content: application/json: schema: $ref: '#/components/schemas/Agreement' 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' default: $ref: 'common.yaml#/responses/UnexpectedError' /agreements/{agreementId}/cancel: parameters: - $ref: '#/components/parameters/agreementId' post: tags: - requestor operationId: cancelAgreement summary: CancelAgreement - Cancels Agreement. description: > It is only possible before Provider approved or rejected the Agreement, and before its Expiration. Causes: - the awaiting `approveAgreement` on Provider side to return with `Cancelled` response. - the awaiting `waitForApproval` local call to return with `Cancelled` response. requestBody: $ref: '#/components/requestBodies/Reason' responses: 204: description: Agreement cancelled. 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 410: $ref: 'common.yaml#/responses/Gone' description: Agreement not in `Proposal` nor `Pending` state. default: $ref: 'common.yaml#/responses/UnexpectedError' /agreements/{agreementId}/confirm: parameters: - $ref: '#/components/parameters/agreementId' - $ref: 'common.yaml#/parameters/appSessionId' post: tags: - requestor operationId: confirmAgreement summary: ConfirmAgreement - Sends Agreement proposal to the Provider. description: > Signs self-created Agreement and sends it to the Provider. This call should immediately follow `createAgreement`. responses: 204: description: Agreement confirmed. 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 410: $ref: 'common.yaml#/responses/Gone' description: Agreement not in `Proposal` state. default: $ref: 'common.yaml#/responses/UnexpectedError' /agreements/{agreementId}/wait: parameters: - $ref: '#/components/parameters/agreementId' - $ref: 'common.yaml#/parameters/ackTimeout' post: tags: - requestor operationId: waitForApproval summary: WaitForApproval - Waits for Agreement approval by the Provider. description: > This is a blocking operation. The call may be aborted by Requestor caller code. After the call is aborted or timed out, another `waitForApproval` call can be raised on the same Agreement Id. responses: 204: description: > Agreement approved by the Provider. The Providers’s corresponding `approveAgreement` call returns `204` (Approved) **before** this endpoint on the Requestor side. The Provider is now ready to accept a request to start an Activity. 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 408: $ref: 'common.yaml#/responses/Timeout' description: Agreement not approved within given timeout. Try again. 409: $ref: 'common.yaml#/responses/Conflict' description: Agreement not confirmed yet by Requestor himself. 410: $ref: 'common.yaml#/responses/Gone' description: > Agreement is not approved. This state is permanent. Attached `ErrorMessage` contains further details: - `Rejected` - Indicates that the Provider has called `rejectAgreement`, which effectively stops the Agreement handshake. The Requestor may attempt to return to the Negotiation phase by sending a new Proposal or to the Agreement phase by creating new Agreement. - `Cancelled` - Indicates that the Requestor himself has called `cancelAgreement`, which effectively stops the Agreement handshake. - `Expired` - Indicates that Agreement validity period elapsed and it was not approved, rejected nor cancelled. - `Terminated` - Indicates that Agreement is already terminated. default: $ref: 'common.yaml#/responses/UnexpectedError' /agreementEvents: parameters: - $ref: 'common.yaml#/parameters/pollTimeout' - $ref: 'common.yaml#/parameters/afterTimestamp' - $ref: 'common.yaml#/parameters/maxEvents' - $ref: 'common.yaml#/parameters/appSessionId' get: tags: - requestor - provider operationId: collectAgreementEvents summary: CollectAgreementEvents - Collects events related to an Agreement. description: > This is a blocking operation. It will not return until there is at least one new event. All events are appearing on both sides equally. Returns Agreement related events: * `AgreementApprovedEvent` - Indicates that the Agreement has been approved by the Provider. - The Provider is now ready to accept a request to start an Activity as described in the negotiated agreement. - The Providers’s corresponding `approveAgreement` call returns `Approved` after this event is emitted. * `AgreementRejectedEvent` - Indicates that the Provider has called `rejectAgreement`, which effectively stops the Agreement handshake. The Requestor may attempt to return to the Negotiation phase by sending a new Proposal. * `AgreementCancelledEvent` - Indicates that the Requestor has called `cancelAgreement`, which effectively stops the Agreement handshake. * `AgreementTerminatedEvent` - Indicates that the Agreement has been terminated by specified party (contains signature). * `AgreementTerminationNoticeEvent` - Indicates that the Provider announced its intention to terminate the Agreement (see `postAgreementTerminationNotice`). The Agreement stays `Approved` and existing Activities may continue during the grace period; the Requestor should finish or migrate its work by `terminationDeadline`. Exactly one such event is ever emitted per Agreement. responses: 200: $ref: '#/components/responses/AgreementEventList' 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' description: Unknown appSessionId given. default: $ref: 'common.yaml#/responses/UnexpectedError' /agreements/{agreementId}/approve: parameters: - $ref: '#/components/parameters/agreementId' - $ref: 'common.yaml#/parameters/appSessionId' - $ref: 'common.yaml#/parameters/ackTimeout' post: tags: - provider operationId: approveAgreement summary: ApproveAgreement - Approves Agreement proposed by the Reqestor. description: > This is a blocking operation. The call may be aborted by Provider caller code. After the call is aborted or timed out, another `approveAgreement` call can be raised on the same `agreementId`. **Note**: It is expected from the Provider node implementation to “ring-fence” the resources required to fulfill the Agreement before the ApproveAgreement is sent. However, the resources should not be fully committed until `Approved` response is received from the `approveAgreement` call. **Note**: Mutually exclusive with `rejectAgreement`. responses: 204: description: > Agreement approved. Indicates that the approved Agreement has been successfully delivered to the Requestor and acknowledged. - The Requestor side has been notified about the Provider’s commitment. - The Provider is now ready to accept a request to start an Activity. - The Requestor’s corresponding `waitForApproval` call returns `204` (Approved) **after** this endpoint on the Provider side. 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 408: $ref: 'common.yaml#/responses/Timeout' description: Agreement not approved within given timeout. Try again. 410: $ref: 'common.yaml#/responses/Gone' description: > Agreement approval failed permanently. Attached `ErrorMessage` contains further details: - `Rejected` - Indicates that the Provider himself has already called `rejectAgreement`. - `Cancelled` - Indicates that before Provider approved this Agreement, the Requestor has called `cancelAgreement`, thus invalidating the Agreement. The Provider may attempt to return to the Negotiation phase by sending a new Proposal. - `Expired` - Indicates that Agreement validity period elapsed and it was not approved, rejected nor cancelled. - `Terminated` - Indicates that Agreement is already terminated. default: $ref: 'common.yaml#/responses/UnexpectedError' /agreements/{agreementId}/reject: parameters: - $ref: '#/components/parameters/agreementId' post: tags: - provider operationId: rejectAgreement summary: RejectAgreement - Rejects Agreement proposed by the Requestor. description: > The Requestor side is notified about the Provider’s decision to reject a negotiated agreement. This effectively stops the Agreement handshake. **Note**: Mutually exclusive with `approveAgreement`. requestBody: $ref: '#/components/requestBodies/Reason' responses: 204: description: Agreement rejected. 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 410: $ref: 'common.yaml#/responses/Gone' description: > Agreement rejection failed permanently. Attached `ErrorMessage` contains further details: - `Rejected` - Indicates that the Provider himself has already called `rejectAgreement`. - `Cancelled` - Indicates that before Provider rejected this Agreement, the Requestor has called `cancelAgreement`, thus invalidating the Agreement. The Provider may attempt to return to the Negotiation phase by sending a new Proposal. - `Expired` - Indicates that Agreement validity period elapsed and it was not approved, rejected nor cancelled. - `Terminated` - Indicates that Agreement is already terminated. default: $ref: 'common.yaml#/responses/UnexpectedError' /agreements/{agreementId}/terminate: parameters: - $ref: '#/components/parameters/agreementId' post: tags: - provider - requestor operationId: terminateAgreement summary: TerminateAgreement - Terminates approved Agreement. description: > Method to finish/close the Agreement while in `Approved` state. The other party gets notified about calling party decision to terminate a "running" agreement. **Note**: Can be invoked at any time after Agreement was approved by both sides. **Note**: When the Provider has announced a termination notice for the Agreement (see `postAgreementTerminationNotice`), the Provider's own call is refused with `409 Conflict` until `terminationDeadline` has passed - the grace period promised to the Requestor cannot be cut short. Without a notice the Provider's termination path is unchanged, and the Requestor may terminate at any time. **Note**: Financial and reputational consequences are not defined by this specification. requestBody: $ref: '#/components/requestBodies/Reason' responses: 204: description: Agreement terminated. 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' 409: $ref: 'common.yaml#/responses/Conflict' description: > Agreement can not be terminated yet (is in `Proposal` or `Pending` state), or the Provider announced a termination notice whose deadline has not passed. 410: $ref: 'common.yaml#/responses/Gone' description: > Agreement termination failed permanently. Attached `ErrorMessage` contains further details: - `Rejected` - Indicates that the Provider has rejected this Agreement. - `Cancelled` - Indicates the Requestor has called cancelled this Agreement. - `Expired` - Indicates that Agreement validity period elapsed and it was not approved, rejected nor cancelled. - `Terminated` - Indicates that Agreement is already terminated. default: $ref: 'common.yaml#/responses/UnexpectedError' /agreements/{agreementId}/terminate/reason: parameters: - $ref: '#/components/parameters/agreementId' post: tags: - provider - requestor operationId: getTerminateAgreementReason summary: Gets termination reason reported when terminateAgreement operation was called. description: > Method to get the reason for terminating the Agreement. responses: 200: $ref: '#/components/responses/AgreementTerminationReason' 400: $ref: 'common.yaml#/responses/BadRequest' 401: $ref: 'common.yaml#/responses/Unauthorized' 404: $ref: 'common.yaml#/responses/NotFound' default: $ref: 'common.yaml#/responses/UnexpectedError' /agreements/{agreementId}/terminationNotice: parameters: - $ref: '#/components/parameters/agreementId' - $ref: 'common.yaml#/parameters/ackTimeout' post: tags: - provider operationId: postAgreementTerminationNotice summary: PostAgreementTerminationNotice - Announces the Provider's intention to terminate an Agreement. description: > Sends the Requestor a termination notice for an Approved Agreement. The Agreement remains `Approved` and its existing Activities may continue. The Requestor is expected to finish or migrate its work by `terminationDeadline`; once that deadline has passed, the Provider may explicitly terminate the Agreement. Until then the Provider's own `terminateAgreement` is refused for this Agreement, while the Requestor may terminate at any time. The call waits for the Requestor's node to record and acknowledge the notice; the optional `timeout` parameter bounds that wait. A `204` response means the Requestor's node recorded the notice - not that the Requestor application has already consumed the event. Only one notice may be recorded per Agreement and its `terminationDeadline` and `reason` are immutable once acknowledged. A repeated request with the same payload is acknowledged again without creating a duplicate event, which makes retry safe after an acknowledgement timeout; a request with a different payload returns `409 Conflict`. Available only to the Provider identity associated with the Agreement. Posting a notice does not change the Agreement state. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AgreementTerminationNotice' responses: 204: description: The Requestor's node recorded the notice. 400: $ref: 'common.yaml#/responses/BadRequest' description: The termination deadline is invalid or is not in the future. 401: $ref: 'common.yaml#/responses/Unauthorized' 403: $ref: 'common.yaml#/responses/Forbidden' description: The calling identity is not the Provider for this Agreement. 404: $ref: 'common.yaml#/responses/NotFound' 408: $ref: 'common.yaml#/responses/Timeout' description: The Requestor did not acknowledge the notice before the timeout. 409: $ref: 'common.yaml#/responses/Conflict' description: The Agreement is not Approved or the notice conflicts with an already recorded notice. 410: $ref: 'common.yaml#/responses/Gone' description: The Agreement is already in a terminal state. default: $ref: 'common.yaml#/responses/UnexpectedError' components: securitySchemes: app_key: $ref: 'common.yaml#/components/securitySchemes/app_key' parameters: subscriptionId: name: subscriptionId in: path required: true schema: type: string queryId: name: queryId in: path required: true schema: type: string proposalId: name: proposalId in: path required: true schema: type: string agreementId: name: agreementId in: path required: true schema: type: string eventPeerId: description: > allows to query offers from specified node. name: peerId in: query required: false schema: type: string requestBodies: Offer: required: true content: application/json: schema: $ref: '#/components/schemas/DemandOfferBase' Demand: required: true content: application/json: schema: $ref: '#/components/schemas/DemandOfferBase' Proposal: required: true content: application/json: schema: $ref: '#/components/schemas/DemandOfferBase' Reason: required: false content: application/json: schema: $ref: 'common.yaml#/components/schemas/Reason' AgreementProposal: required: true content: application/json: schema: $ref: '#/components/schemas/AgreementProposal' PropertyQueryReply: required: true content: application/json: schema: $ref: '#/components/schemas/PropertyQueryReply' NewScan: required: true content: application/json: schema: $ref: '#/components/schemas/NewScan' responses: ScanId: description: Market scan start. content: application/json: schema: type: string description: Iterator id SubscriptionId: description: Subscribed. content: application/json: schema: type: string description: Subscription id Proposal: description: Proposal. content: application/json: schema: $ref: '#/components/schemas/Proposal' ProposalId: description: Counter Proposal created. content: application/json: schema: type: string description: Proposal Id DemandList: description: Demand list. content: application/json: schema: type: array items: $ref: '#/components/schemas/Demand' OfferList: description: Offer list. content: application/json: schema: type: array items: $ref: '#/components/schemas/Offer' ScanEvents: description: Scan Events content: application/json: schema: type: array items: $ref: '#/components/schemas/Offer' EventList: description: Proposal or Agreement event list. content: application/json: schema: type: array items: $ref: '#/components/schemas/Event' AgreementEventList: description: Agreement-related event list. content: application/json: schema: type: array items: $ref: '#/components/schemas/AgreementOperationEvent' AgreementTerminationReason: description: Agreement termination reason. content: application/json: schema: $ref: '#/components/schemas/AgreementTerminatedEvent' AgreementList: description: Result of listing agreements. content: application/json: schema: type: array items: $ref: '#/components/schemas/AgreementListEntry' schemas: AgreementValidTo: type: string format: date-time description: > End of validity period. Agreement needs to be approved, rejected or cancelled before this date; otherwise will expire. DemandOfferBase: type: object required: - properties - constraints properties: properties: description: > The object which includes all the Demand/Offer/Proposal properties. This is a JSON object in "flat convention" - where keys are full property names and their values indicate properties. The value's Javascript type shall conform with the type of the property (as indicated in Golem Standards). ### Example property object: ``` { "golem.com.pricing.model":"linear", "golem.com.pricing.model.linear.coeffs":[0.001, 0.002, 0.0], "golem.com.scheme":"payu", "golem.com.scheme.payu.interval_sec":6.0, "golem.com.usage.vector":["golem.usage.duration_sec","golem.usage.cpu_sec"], "golem.inf.cpu.architecture":"x86_64", "golem.inf.cpu.cores":4, "golem.inf.cpu.threads":7, "golem.inf.mem.gib":10.612468048930168, "golem.inf.storage.gib":81.7227783203125, "golem.node.debug.subnet":"market-devnet", "golem.node.id.name":"tworec@mf-market-devnet", "golem.runtime.name":"vm", "golem.runtime.version@v":"0.1.0" } ``` type: object constraints: type: string Demand: allOf: - $ref: '#/components/schemas/DemandOfferBase' - type: object required: - demandId - requestorId - timestamp properties: demandId: type: string readOnly: true requestorId: type: string readOnly: true timestamp: $ref: 'common.yaml#/components/schemas/Timestamp' Offer: allOf: - $ref: '#/components/schemas/DemandOfferBase' - type: object required: - offerId - providerId - timestamp properties: offerId: type: string readOnly: true providerId: type: string readOnly: true timestamp: $ref: 'common.yaml#/components/schemas/Timestamp' Proposal: allOf: - $ref: '#/components/schemas/DemandOfferBase' - type: object required: - proposalId - issuerId - state - timestamp properties: proposalId: type: string readOnly: true issuerId: type: string readOnly: true state: type: string readOnly: true enum: [ Initial, Draft, Rejected, Accepted, Expired ] description: > * `Initial` - proposal arrived from the market as response to subscription * `Draft` - bespoke counter-proposal issued by one party directly to other party (negotiation phase) * `Rejected` by other party * `Accepted` - promoted into the Agreement draft * `Expired` - not accepted nor rejected before validity period timestamp: $ref: 'common.yaml#/components/schemas/Timestamp' prevProposalId: type: string description: > id of the proposal from other side which this proposal responds to AgreementProposal: type: object required: - proposalId - validTo properties: proposalId: type: string description: id of the proposal to be promoted to the Agreement validTo: $ref: '#/components/schemas/AgreementValidTo' AgreementState: type: string enum: [ Proposal, Pending, Cancelled, Rejected, Approved, Expired, Terminated ] description: > * `Proposal` - newly created by a Requestor (draft based on Proposal) * `Pending` - confirmed by a Requestor and send to Provider for approval * `Cancelled` by a Requestor * `Rejected` by a Provider * `Approved` by both sides * `Expired` - not approved, rejected nor cancelled within validity period * `Terminated` - finished after approval. Agreement: type: object required: - agreementId - demand - offer - validTo - state - timestamp properties: agreementId: type: string demand: $ref: '#/components/schemas/Demand' offer: $ref: '#/components/schemas/Offer' validTo: $ref: '#/components/schemas/AgreementValidTo' approvedDate: type: string format: date-time description: Agreement approval timestamp state: $ref: '#/components/schemas/AgreementState' timestamp: $ref: 'common.yaml#/components/schemas/Timestamp' appSessionId: $ref: 'common.yaml#/components/schemas/AppSessionId' proposedSignature: type: string approvedSignature: type: string committedSignature: type: string PropertyQuery: type: object required: - queriedProperties properties: issuerProperties: type: object queryId: type: string queriedProperties: uniqueItems: false type: array items: type: string PropertyQueryReply: type: object NewScan: description: > type: object properties: timeout: type: number format: int32 description: > specifies how long an unused iterator will live in the server's memory. The value may be unspecified, defaulting to 30 seconds. This is intended to protect the server from memory leaks in applications that do not clean up their resources. type: $ref: '#/components/schemas/ScanType' constraints: description: > optional filter. type: string required: - type ScanType: description: > scan type. offer for offers. demand for demands. type: string enum: - offer - demand Event: type: object required: - eventType - eventDate discriminator: propertyName: eventType properties: eventType: type: string eventDate: $ref: 'common.yaml#/components/schemas/Timestamp' PropertyQueryEvent: allOf: - $ref: '#/components/schemas/Event' - type: object required: - propertyQuery properties: propertyQuery: $ref: '#/components/schemas/PropertyQuery' ProposalEvent: allOf: - $ref: '#/components/schemas/Event' - type: object required: - proposal properties: proposal: $ref: '#/components/schemas/Proposal' ProposalRejectedEvent: allOf: - $ref: '#/components/schemas/Event' - type: object required: - proposalId properties: proposalId: type: string readOnly: true reason: $ref: 'common.yaml#/components/schemas/Reason' AgreementEvent: allOf: - $ref: '#/components/schemas/Event' - type: object required: - agreement properties: agreement: $ref: '#/components/schemas/Agreement' AgreementListEntry: type: object required: - id - creationTs - approveTs - role discriminator: propertyName: eventType properties: id: type: string timestamp: $ref: 'common.yaml#/components/schemas/Timestamp' approvedDate: $ref: 'common.yaml#/components/schemas/Timestamp' role: type: string AgreementOperationEvent: allOf: - $ref: '#/components/schemas/Event' - type: object required: - agreementId discriminator: propertyName: eventType properties: agreementId: type: string AgreementApprovedEvent: allOf: - $ref: '#/components/schemas/AgreementOperationEvent' AgreementRejectedEvent: allOf: - $ref: '#/components/schemas/AgreementOperationEvent' - type: object properties: reason: $ref: 'common.yaml#/components/schemas/Reason' AgreementCancelledEvent: allOf: - $ref: '#/components/schemas/AgreementOperationEvent' - type: object properties: reason: $ref: 'common.yaml#/components/schemas/Reason' AgreementTerminatedEvent: description: > One party terminated Agreement. Termination Reason and signature can be retrieved from event. allOf: - $ref: '#/components/schemas/AgreementOperationEvent' - type: object required: - terminator - signature properties: terminator: type: string enum: [ Requestor, Provider ] signature: type: string reason: $ref: 'common.yaml#/components/schemas/Reason' AgreementTerminationNotice: type: object required: - terminationDeadline properties: terminationDeadline: $ref: 'common.yaml#/components/schemas/Timestamp' description: > Absolute time by which the Provider expects the Requestor to finish or migrate its work. It must be later than the time at which the notice is posted. reason: $ref: 'common.yaml#/components/schemas/Reason' AgreementTerminationNoticeEvent: description: > The Provider announced its intention to terminate this Agreement. The Agreement remains `Approved` and existing Activities may continue during the grace period. The Requestor should finish or migrate its work by `terminationDeadline`, after which the Provider may terminate the Agreement. Exactly one such event is ever recorded per Agreement and its payload is immutable. `eventDate` is the moment the Requestor's node recorded the notice; `reason` carries the Provider's message verbatim. allOf: - $ref: '#/components/schemas/AgreementOperationEvent' - type: object required: - terminationDeadline properties: terminationDeadline: $ref: 'common.yaml#/components/schemas/Timestamp' reason: $ref: 'common.yaml#/components/schemas/Reason'