{"openapi":"3.1.0","info":{"contact":{"email":"info@dke-data.com","name":"DKE Data","url":"https://dke-data.com"},"title":"agrirouter G4 API","version":"1.0","description":"This service provides access to agrirouter API through modern RESTful interface called G4 (for gateway id = 4).\n"},"servers":[{"url":"https://api.agrirouter.com","description":"Production Server"},{"url":"https://api.qa.agrirouter.farm","description":"QA Server"}],"paths":{"/messages":{"post":{"operationId":"sendMessages","summary":"Send one or several messages to agrirouter inbox","description":"Send one or several messages via agrirouter to other endpoints.\nThe payload is sent as a binary stream in the request body.\nIf the payload is too large, it would be split into several messages\nby agrirouter itself, client does not need to care about doing that.\nDepending on size of the payload, result could be a single message\nor several messages in the target endpoint outboxes.\n","parameters":[{"name":"content-length","in":"header","required":true,"schema":{"type":"integer","format":"int64"},"description":"The size of the complete payload in bytes.\nThis is used to determine if the payload needs to be \nsplit into chunks and how.\n"},{"name":"x-agrirouter-is-publish","in":"header","required":true,"schema":{"type":"boolean"},"description":"If set to true, the message will be sent as a published message\nand any endpoints that are subscribed to the message type\nwould be able to receive it, provided other conditions for routing are met.\n"},{"name":"x-agrirouter-direct-recipients","in":"header","required":false,"schema":{"type":"array","items":{"type":"string","format":"uuid"}},"description":"Comma-separated list of agrirouter endpoint IDs of the direct recipients.\nAllows specifying direct recipients of the message, which\ncould receive it even if they are not subscribed to the message type.\n"},{"name":"x-agrirouter-sent-timestamp","in":"header","required":true,"schema":{"type":"string","format":"date-time"},"description":"Client side timestamp of sending the data.\n"},{"name":"x-agrirouter-endpoint-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"},"description":"The agrirouter endpoint ID of the sender.\nThis is the ID of the endpoint that is sending the message.\n"},{"name":"x-agrirouter-teamset-context-id","in":"header","required":false,"schema":{"type":"string","maxLength":100},"description":"A teamset is a set of connected machines that work and move together \nand are connected to the same (virtual) communication unit. \nThe machines in the teamset are typically connected physically and \ninformationally (for example via ISOBUS).\n"},{"name":"x-agrirouter-message-type","in":"header","required":true,"schema":{"type":"string","maxLength":100},"description":"Message type of the sent data. See available types here:\nhttps://docs.agrirouter.com/agrirouter-interface-documentation/latest/tmt/overview.html\n","examples":{"iso11783DeviceDescriptionProtobuf":{"summary":"Device Description","value":"iso:11783:-10:device_description:protobuf"},"iso11783TaskDataZip":{"summary":"ISO11783 Task Data Zip","value":"iso:11783:-10:taskdata:zip"}}},{"$ref":"#/components/parameters/x-agrirouter-tenant-id"},{"name":"x-agrirouter-context-id","in":"header","required":true,"schema":{"type":"string","maxLength":50},"description":"Application side identifier of the sent data.\nagrirouter will use this to generate application message id\nand also will pass it on as chunk context id in case if the payload\nhad to be split into several messages.\nThis has to be generated by the application and be unique for\nevery sent payload. Applications may want to reuse the same id\nin case if they are resending the same payload again, when f.e\nretrying after a failure.\n"},{"name":"x-agrirouter-filename","in":"header","required":false,"schema":{"type":"string","maxLength":100},"description":"Optional name of the file that is attached to messages as metadata.\n"}],"requestBody":{"required":true,"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"Message successfully sent to inbox"},"400":{"description":"Request is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authorization failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Content too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server Side Error"}}}},"/events":{"get":{"operationId":"receiveEvents","summary":"Receive events from agrirouter outbox","parameters":[{"name":"types","in":"query","required":false,"description":"Events type filter, if provided would limit the events returned to only those of the specified types.\nIf not provided, all supported events will be streamed.\n","example":["MESSAGE_RECEIVED","FILE_RECEIVED","AUTHORIZATION_ADDED"],"schema":{"type":"array","items":{"type":"string","enum":["MESSAGE_RECEIVED","FILE_RECEIVED","ENDPOINT_DELETED","ENDPOINTS_LIST_CHANGED","AUTHORIZATION_ADDED","AUTHORIZATION_REVOKED"]}}}],"description":"Receive stream of events from the agrirouter outbox.\nThe events are retrieved for every endpoint of an\nauthorized application.\n\nThese are possible event types:\n- MESSAGE_RECEIVED - when one message is received\n- FILE_RECEIVED - when chunked payload has been completely received\n- ENDPOINTS_LIST_CHANGED - when the list of endpoints in a tenant changes\n- AUTHORIZATION_ADDED - when a tenant authorization is newly added\n- AUTHORIZATION_REVOKED - when a tenant authorization is revoked\n\nThese events are sent as Server-Sent Events (SSE), where one line\nprefixed \"event:\" would define event type and another line\nprefixed \"data:\" would contain the actual event data.\n\nSee Server-Sent Events specification here:\nhttps://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events\n\nFor example:\n\n```\nevent: MESSAGE_RECEIVED\ndata: {\"messageId\":\"12345\",\"timestamp\":\"2023-01-01T12:00:00Z\"}\n```\n\nIn this API, `data` would always be JSON encoded object, every\nevent data schema is defined in the `#/components/schemas`, with\nschema name always ending with `EventData`. \n\nHere is a table:\n\n| Event Type          | Schema                                                                     |\n|---------------------|----------------------------------------------------------------------------|\n| MESSAGE_RECEIVED    | [MessageReceivedEventData](#/components/schemas/MessageReceivedEventData)  |\n| FILE_RECEIVED       | [FileReceivedEventData](#/components/schemas/FileReceivedEventData)        |\n| ENDPOINT_DELETED    | [EndpointDeletedEventData](#/components/schemas/EndpointDeletedEventData)  |\n| ENDPOINTS_LIST_CHANGED | [EndpointsListChangedEventData](#/components/schemas/EndpointsListChangedEventData) |\n| AUTHORIZATION_ADDED | [AuthorizationAddedEventData](#/components/schemas/AuthorizationAddedEventData) |\n| AUTHORIZATION_REVOKED | [AuthorizationRevokedEventData](#/components/schemas/AuthorizationRevokedEventData) |\n","responses":{"200":{"description":"Stream of events from agrirouter","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/GenericEventData"}}}},"400":{"description":"Request is invalid"},"401":{"description":"Authentication failed"},"403":{"description":"Authorization failed"},"500":{"description":"Server Side Error"}}}},"/confirmations":{"post":{"operationId":"confirmMessages","summary":"Confirm received messages","description":"Confirm that messages have been received and processed by the application.\nEach confirmation carries a message ID and the endpoint ID that received it.\nThe same message may be received by different endpoints and can be confirmed\nseparately, either in the same request or in different ones.\n","parameters":[{"$ref":"#/components/parameters/x-agrirouter-tenant-id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmMessagesRequest"}}}},"responses":{"202":{"description":"Confirmation is saved for processing, feed will be updated eventually"},"400":{"description":"Request is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authorization failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server Side Error"}}}},"/tenants/{tenantId}/endpoints":{"get":{"operationId":"listTenantEndpoints","summary":"List tenant endpoints with route information","description":"Returns the current list of endpoints in the tenant together with their\ncapability information.\n\nFor endpoints owned by the authorized application, this operation also\nreturns route-derived maps describing which endpoints they can send to\nand receive from for each message type.\n\nThis operation is tenant-scoped and is intended for inspecting or\nrefreshing endpoint information for one already-known tenant. Use it\nfor example if you cannot/do not want to persist information from the\n`ENDPOINT_LIST_CHANGED` event or if your frontend doesn't have access to that\ndata.\n\nIt is not intended as the primary application-start or global re-sync operation.\nFor that purpose, use `GET /tenants`, which returns all currently\nauthorized tenants together with their related endpoints.\n","parameters":[{"$ref":"#/components/parameters/tenantId"}],"responses":{"200":{"description":"Tenant endpoints successfully retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EndpointsListResponse"}}}},"400":{"description":"Request is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authorization failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server Side Error"}}}},"/tenants":{"get":{"operationId":"listAuthorizedTenants","summary":"List all authorized tenants and their related endpoints","description":"Returns all tenants for which the current application has an existing\nauthorization together with the related endpoints known for each tenant.\n\nThis operation is intended as the primary global synchronization\nendpoint, for example when an application starts, recovers after a\ncrash, or otherwise needs to rebuild its complete tenant state.\n","responses":{"200":{"description":"Authorized tenants successfully retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantsListResponse"}}}},"400":{"description":"Request is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authorization failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server Side Error"}}}},"/endpoints/{externalId}":{"put":{"operationId":"putEndpoint","summary":"Create or update endpoint","description":"This resource could be used to create new endpoint or reconfigure existing one.","security":[{"agrirouterOauthQA":["endpoints:manage"]},{"agrirouterOauthPROD":["endpoints:manage"]}],"parameters":[{"$ref":"#/components/parameters/x-agrirouter-tenant-id"},{"$ref":"#/components/parameters/externalId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PutEndpointRequest"}}}},"responses":{"200":{"description":"Endpoint was successfully updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Endpoint"}}}},"201":{"description":"Endpoint was successfully created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Endpoint"}}}},"400":{"description":"Request is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authorization failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"413":{"description":"Content too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server Side Error"},"502":{"description":"Bad Gateway, upstream service has returned an error"},"503":{"description":"Service Unavailable at the moment"},"504":{"description":"Gateway Timeout, request took too long to process"}}},"delete":{"operationId":"deleteEndpoint","summary":"Delete endpoint","description":"Delete endpoint by external ID. This would remove the endpoint from agrirouter and it would no longer receive messages.","security":[{"agrirouterOauthQA":["endpoints:manage"]},{"agrirouterOauthPROD":["endpoints:manage"]}],"parameters":[{"$ref":"#/components/parameters/x-agrirouter-tenant-id"},{"$ref":"#/components/parameters/externalId"}],"responses":{"204":{"description":"Endpoint successfully deleted"},"400":{"description":"Request is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Authorization failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Endpoint with the specified external ID not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server Side Error"}}}}},"security":[{"agrirouterOauthQA":[]},{"agrirouterOauthPROD":[]}],"components":{"securitySchemes":{"agrirouterOauthQA":{"type":"oauth2","description":"Agrirouter OAuth2 authentication for QA environment.","flows":{"clientCredentials":{"tokenUrl":"https://oauth.qa.agrirouter.farm/token","scopes":{}}}},"agrirouterOauthPROD":{"type":"oauth2","description":"Agrirouter OAuth2 authentication for PROD environment.","flows":{"clientCredentials":{"tokenUrl":"https://api-oauth.agrirouter.com/token","scopes":{}}}}},"parameters":{"x-agrirouter-tenant-id":{"name":"x-agrirouter-tenant-id","in":"header","required":true,"schema":{"type":"string","format":"uuid"},"description":"The farmer's tenant ID in relation to which communication is done."},"tenantId":{"name":"tenantId","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The farmer's tenant ID in relation to which this operation is performed."},"externalId":{"name":"externalId","in":"path","required":true,"schema":{"type":"string","minLength":3,"maxLength":255,"pattern":"^([uU][rR][nN]:)?[a-zA-Z0-9][a-zA-Z0-9-]{0,31}:[a-zA-Z0-9()+,\\-.:=@;$_!*%/?#]+$"},"description":"Application-defined external ID of the endpoint. SHOULD be formatted as a\nURN as defined by RFC 8141 (e.g. `urn:my-app:endpoint:42`). The `urn:`\nprefix itself is optional for backwards compatibility, but the value must\nalways contain a namespace identifier and a namespace-specific string\nseparated by a colon. The URN namespace identifier and namespace-specific\nstring allow applications to scope their endpoint IDs in a stable,\nglobally unique way.\n"}},"schemas":{"GenericEventData":{"oneOf":[{"$ref":"#/components/schemas/MessageReceivedEventData"},{"$ref":"#/components/schemas/FileReceivedEventData"},{"$ref":"#/components/schemas/EndpointDeletedEventData"},{"$ref":"#/components/schemas/EndpointsListChangedEventData"},{"$ref":"#/components/schemas/AuthorizationAddedEventData"},{"$ref":"#/components/schemas/AuthorizationRevokedEventData"}],"discriminator":{"propertyName":"event_type"}},"PayloadURI":{"type":"string","format":"uri","description":"The URI to access the payload. May have hostname that is different from\nthe API server, as payloads may be served from a different server or CDN.\nClients MUST use provided URI as is without any modifications.\nIf event embeds payload directly, this field would be absent.\n"},"MessageReceivedEventData":{"type":"object","description":"Data structure for MESSAGE_RECEIVED events. This event would arrive whenever application\ngot a message routed to one of its endpoints.\n","required":["id","message_type","app_message_id","sent_at","event_type","receiving_endpoint_id"],"properties":{"id":{"type":"string","format":"uuid","description":"The agrirouter message ID of the received message, generated by agrirouter.\nUse this value as `message_id` when confirming the message via `POST /confirmations`.\n"},"app_message_id":{"type":"string","description":"The application message ID of the received message, generated based on application input."},"message_type":{"type":"string","example":"iso:11783:-10:taskdata:zip","description":"The message type of the received message.\nSee available types here:\nhttps://docs.agrirouter.com/agrirouter-interface-documentation/latest/tmt/overview.html\n"},"sent_at":{"type":"string","format":"date-time","description":"The timestamp when the message was sent by sending application."},"received_at":{"type":"string","format":"date-time","description":"The timestamp when the message was received by agrirouter."},"payload":{"type":"string","format":"byte","description":"The payload of the message, base64 encoded. Only one of `payload` or `payload_uri` would be present."},"payload_uri":{"$ref":"#/components/schemas/PayloadURI"},"event_type":{"type":"string","const":"MESSAGE_RECEIVED"},"receiving_endpoint_id":{"type":"string","format":"uuid","description":"Internally-generated agrirouter ID of the receiving endpoint."},"filename":{"type":"string","description":"Optional name of the file that is attached to messages as metadata."},"tenant_id":{"type":"string","description":"The tenant ID of the to which receiving endpoint belongs. This is useful for confirming messages back to agrirouter."},"teamset_context_id":{"type":"string","description":"The teamset context ID that was provided by sending application when sending the message, if any."}}},"EndpointDeletedEventData":{"type":"object","description":"Data structure for ENDPOINT_DELETED events. This event would arrive whenever one of the endpoints of the application is deleted from agrirouter, either by this API or by other means.\n","required":["id","external_id","event_type"],"properties":{"id":{"type":"string","format":"uuid","description":"The agrirouter endpoint ID of the deleted endpoint."},"external_id":{"type":"string","description":"The external ID of the deleted endpoint, which was provided when creating or updating the endpoint."},"event_type":{"type":"string","const":"ENDPOINT_DELETED"}}},"EndpointsListChangedEventData":{"type":"object","description":"Data structure for ENDPOINTS_LIST_CHANGED events. This event would\narrive whenever the set of endpoints visible to the application, or\ntheir respective capabilities and/or routes, change in a tenant.\n\nENDPOINTS_LIST_CHANGED is only emitted once the application has at\nleast one endpoint of its own in the target tenant. Until that first\napplication-owned endpoint exists, changes to other endpoints in the\ntenant are not reported, even if an authorization is in place. Once\nthe first own endpoint is created, clients receive events for any\nsubsequent change to the visible endpoint set.\n","required":["event_type","tenant_id","endpoints"],"properties":{"event_type":{"type":"string","const":"ENDPOINTS_LIST_CHANGED"},"tenant_id":{"type":"string","format":"uuid","description":"The tenant whose endpoint list changed."},"endpoints":{"type":"array","description":"Complete current list of endpoints in the tenant that are visible\nto the application.\n","items":{"$ref":"#/components/schemas/TenantEndpointInfo"}}}},"AuthorizationAddedEventData":{"type":"object","description":"Data structure for AUTHORIZATION_ADDED events. This event would arrive\nwhenever a user adds an authorization for a tenant to the current\napplication.\n\nAn authorization is uniquely identified by the triple\n(tenant_id, application_id, scope). The application_id is implicit from\nthe receiving subscription; tenant_id and scope are explicit on this\nevent. At present the only scope in use is `endpoints:manage`;\nadditional scopes may be added in the future, and clients should then\ntreat authorizations with different scopes as distinct authorizations\neven when tenant_id matches.\n","required":["event_type","tenant","scope"],"properties":{"event_type":{"type":"string","const":"AUTHORIZATION_ADDED"},"tenant":{"$ref":"#/components/schemas/TenantInfo"},"scope":{"type":"string","description":"The OAuth scope that was granted with this authorization. Today\nthe only scope in use is `endpoints:manage`; additional scopes may\nbe introduced in future revisions of this API.\n","example":"endpoints:manage"}}},"AuthorizationRevokedEventData":{"type":"object","description":"Data structure for AUTHORIZATION_REVOKED events. This event would\narrive whenever a user revokes an authorization for a tenant from the\ncurrent application. When this event is delivered to you, you have\nalready lost access to the target tenant for the given scope. You\nshould clean up all information related to this tenant (for that scope)\nand update your state accordingly.\n\nAll endpoints that were previously accessible via this authorization\nare considered removed. You will receive distinct ENDPOINT_DELETED\nevents for all endpoints deleted as a result of the authorization\nrevocation.\n\nAuthorizations are uniquely identified by\n(tenant_id, application_id, scope); only the authorization matching the\n`scope` below was revoked. At present only the `endpoints:manage`\nscope is in use, but if additional scopes are introduced later, other\nscopes for the same tenant would remain in effect.\n","required":["event_type","tenant_id","scope"],"properties":{"event_type":{"type":"string","const":"AUTHORIZATION_REVOKED"},"tenant_id":{"type":"string","format":"uuid","description":"The tenant whose authorization was revoked."},"scope":{"type":"string","description":"The OAuth scope of the authorization that was revoked. Today the\nonly scope in use is `endpoints:manage`; additional scopes may be\nintroduced in future revisions of this API.\n","example":"endpoints:manage"}}},"FileReceivedEventData":{"type":"object","description":"Data structure for FILE_RECEIVED events. This event shall arrive whenever a big file transfer\nhas completed in its entirety, i.e when big payload was sent as several message chunks, this\nevent would be sent last when the complete payload is received.\n\nTo read payload from this event when using the `payload_uri` field to download\nthe complete payload, it is not required to provide Authorization for this\nrequest, as the URI itself contains access to that specific payload.\n\nThese URIs are time-limited and would expire after at most 15 minutes, so clients \nshould download the payload before that happens.\n","required":["event_type","receiving_endpoint_id","message_type","size","message_ids"],"properties":{"payload_uri":{"$ref":"#/components/schemas/PayloadURI"},"payload":{"type":"string","format":"byte","description":"The payload of the file, base64 encoded. \nOnly one of `payload` or `payload_uri` can be present.\n"},"event_type":{"type":"string","const":"FILE_RECEIVED"},"filename":{"type":"string","description":"Optional name of the file that is attached to messages as metadata."},"receiving_endpoint_id":{"type":"string","format":"uuid","description":"Internally-generated agrirouter ID of the receiving endpoint."},"message_type":{"type":"string","example":"iso:11783:-10:taskdata:zip","description":"The message type of the received payload.\nSee available types here:\nhttps://docs.agrirouter.com/agrirouter-interface-documentation/latest/tmt/overview.html\n"},"size":{"type":"integer","format":"int64","minimum":0,"description":"The size of file payload in bytes."},"message_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"List of agrirouter message IDs of the messages that carried the file payload chunks.\nTo confirm the file, all of these IDs must be confirmed via `POST /confirmations`,\nsince a file may be a concatenation of chunks from the sender.\n"},"tenant_id":{"type":"string","description":"The tenant ID of the to which receiving endpoint belongs. This is useful for confirming messages back to agrirouter."},"teamset_context_id":{"type":"string","description":"The teamset context ID that was provided by sending application when sending the message, if any."}}},"ConfirmMessagesRequest":{"type":"object","required":["confirmations"],"properties":{"confirmations":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/MessageConfirmation"},"description":"List of message confirmations."}}},"MessageConfirmation":{"type":"object","required":["message_id","endpoint_id"],"properties":{"message_id":{"type":"string","format":"uuid","description":"The agrirouter message ID of the confirmed message."},"endpoint_id":{"type":"string","format":"uuid","description":"The agrirouter endpoint ID that received the message."}}},"EndpointsListResponse":{"type":"object","required":["endpoints"],"properties":{"endpoints":{"type":"array","items":{"$ref":"#/components/schemas/TenantEndpointInfo"}}}},"TenantsListResponse":{"type":"object","required":["tenants"],"properties":{"tenants":{"type":"array","items":{"$ref":"#/components/schemas/TenantInfo"}}}},"TenantInfo":{"type":"object","required":["tenant_id","endpoints"],"properties":{"tenant_id":{"type":"string","format":"uuid","description":"Authorized tenant ID."},"endpoints":{"type":"array","description":"Endpoints visible in this tenant, subject to the following\nprivacy rule:\n\n- If the application has not yet created any endpoint of its own\n  in this tenant, this array is empty — even if other endpoints\n  exist in the tenant. This prevents exposing tenant contents to\n  applications that have not yet actively participated in it.\n- Once the application has at least one of its own endpoints in\n  the tenant, this array contains the full set of endpoints\n  visible to the application.\n\nAn authorized tenant with no application-owned endpoint will\ntherefore still appear in `GET /tenants`, but with an empty\n`endpoints` array. See `owned_by_your_application` on\n`TenantEndpointInfo` for the distinction between own and other\nendpoints.\n","items":{"$ref":"#/components/schemas/TenantEndpointInfo"}}}},"TenantEndpointInfo":{"type":"object","required":["id","name","endpoint_type","application_id","tenant_id","owned_by_your_application","capabilities"],"properties":{"id":{"type":"string","format":"uuid","description":"The agrirouter endpoint ID."},"external_id":{"type":"string","description":"External identifier of the endpoint, if available to the caller."},"name":{"type":"string","description":"Display name of the endpoint."},"endpoint_type":{"$ref":"#/components/schemas/EndpointType"},"application_id":{"type":"string","format":"uuid","description":"The ID of the application that owns the endpoint."},"tenant_id":{"type":"string","format":"uuid","description":"The tenant ID of the endpoint."},"owned_by_your_application":{"type":"boolean","description":"Indicates whether this endpoint belongs to the application that is\nauthorized for the current request.\n"},"capabilities":{"$ref":"#/components/schemas/TenantEndpointCapabilities"},"routed_endpoints":{"$ref":"#/components/schemas/RoutedEndpoints"}}},"TenantEndpointCapabilities":{"type":"object","required":["can_send","can_receive"],"properties":{"can_send":{"type":"array","description":"Message types this endpoint can send.","items":{"type":"string"}},"can_receive":{"type":"array","description":"Message types this endpoint can receive.","items":{"type":"string"}}}},"RoutedEndpoints":{"type":"object","description":"Route-derived information for this endpoint.\n\nThis property only exists for endpoints owned by the authorized\napplication. It is omitted for all other endpoints in the tenant.\n","properties":{"can_send_to":{"$ref":"#/components/schemas/EndpointRouteMap"},"can_receive_from":{"$ref":"#/components/schemas/EndpointRouteMap"}}},"EndpointRouteMap":{"type":"object","description":"Map keyed by agrirouter endpoint ID. Each value lists the message types\nfor which routing is currently possible between the two endpoints.\n","additionalProperties":{"type":"array","items":{"type":"string","example":"iso:11783:-10:taskdata:zip"}}},"PutEndpointRequest":{"type":"object","required":["application_id","software_version_id","capabilities","subscriptions","endpoint_type"],"properties":{"name":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[\\p{L}\\p{N} _.,:\\-]+$","description":"Optional name of the endpoint, for easier identification in agrirouter web interface.\nDoes not have to be unique.\nIf not specified, the name would be generated automatically.\n\nWhen provided, must be 1-200 characters long and may contain letters from any\nscript, digits, spaces, and the following special characters: `-`, `_`, `.`, `,`, `:`. \nNames consisting only of whitespace are not allowed as well, which is not\nexpressed in the regex pattern.\n\nIt is not guaranteed that this \"application-set\" name would be used, \nbecause user may override it with \"user-set\" name in agrirouter web interface.\nName send via this API cannot override \"user-set\" name, but\nit can update \"application-set\" name at any time and user can choose to\nswitch name back to \"application-set\".\n"},"application_id":{"type":"string","format":"uuid","description":"The ID of the application that owns the endpoint"},"software_version_id":{"type":"string","format":"uuid","description":"The ID of the software version that owns the endpoint"},"capabilities":{"type":"array","items":{"$ref":"#/components/schemas/EndpointCapability"},"description":"The effective capabilities of the endpoint, must be subset of the capabilities of software version."},"subscriptions":{"type":"array","items":{"$ref":"#/components/schemas/EndpointSubscription"}},"endpoint_type":{"$ref":"#/components/schemas/EndpointTypeToCreate"},"allow_delete_by_user":{"type":"boolean","default":false,"description":"Flag indicating whether the user is allowed to delete this endpoint.\nNote that even when this flag is not set, the user can still force deletion of the endpoint. Applications must handle the ENDPOINT_DELETED event on a best-effort basis. It is also possible that an endpoint is deleted immediately after creation due to a race with the user disconnecting the entire application, so applications should not rely on this flag to prevent endpoint deletion entirely.\n"},"connections_uri":{"type":"string","format":"uri","description":"URI pointing to where the user can manage the entity connected to this endpoint, e.g. to disconnect or delete equipment from an equipment vendor. When provided, this URI will be shown when the user attempts to delete the endpoint, instead of the usual deletion dialog, directing them to the vendor's management page.\n"}}},"Endpoint":{"type":"object","required":["id","external_id","endpoint_type","tenant_id","application_id","software_version_id","capabilities"],"properties":{"id":{"type":"string","format":"uuid"},"external_id":{"type":"string"},"application_id":{"type":"string","format":"uuid"},"software_version_id":{"type":"string","format":"uuid"},"endpoint_type":{"$ref":"#/components/schemas/EndpointType"},"tenant_id":{"type":"string","description":"The tenant ID of the endpoint"},"capabilities":{"type":"array","items":{"$ref":"#/components/schemas/EndpointCapability"}},"allow_delete_by_user":{"type":"boolean","default":false,"description":"Flag indicating whether the user is allowed to delete this endpoint.","readOnly":true},"connections_uri":{"type":"string","format":"uri","description":"URI pointing to where the user can manage the entity connected to this endpoint, e.g. to disconnect or delete equipment from an equipment vendor.\n","readOnly":true}}},"EndpointSubscription":{"type":"object","required":["message_type"],"properties":{"message_type":{"type":"string","example":"iso:11783:-10:taskdata:zip","description":"The message type that the endpoint is subscribed to.\nSee available types here:\nhttps://docs.agrirouter.com/agrirouter-interface-documentation/latest/tmt/overview.html\n"}}},"EndpointCapability":{"type":"object","required":["message_type","direction"],"properties":{"message_type":{"type":"string","example":"iso:11783:-10:taskdata:zip","description":"The message type that the endpoint can send or receive.\nSee available types here:\nhttps://docs.agrirouter.com/agrirouter-interface-documentation/latest/tmt/overview.html\n"},"direction":{"type":"string","enum":["SEND","RECEIVE","SEND_RECEIVE"]}}},"ErrorResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string","description":"A human-readable error message describing what went wrong."}}},"EndpointType":{"type":"string","description":"Type of an endpoint that can be observed in the system. This includes\ntypes that can be created via this G4 API as well as legacy types that\ncan only be created via the G2/G3 APIs. For values accepted when\ncreating an endpoint, see `EndpointTypeToCreate`.\n","enum":["cloud_software","virtual_communication_unit","communication_unit","telemetry_platform"]},"EndpointTypeToCreate":{"type":"string","description":"Type of an endpoint that can be created via this G4 API. Legacy types\nsuch as `communication_unit` and `telemetry_platform` cannot be\ncreated here; see `EndpointType` for the full set that may be observed.\n\n`farming_software` is accepted as a deprecated alias for\n`cloud_software` and will be removed in a future revision.\n","enum":["cloud_software","virtual_communication_unit","farming_software"]}}}}