> For the complete documentation index, see [llms.txt](https://hub.equipme.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hub.equipme.io/development/api-reference-app/ticket-link.md).

# Ticket link

A **ticket link** connects two tickets and says how they relate. Links are directional and are always read from the perspective of the ticket in the path: linking A to B as `BLOCKS` means B shows the link as `BLOCKED_BY`.

| Link           | Counterpart     |
| -------------- | --------------- |
| `SUBTASK_OF`   | `PARENT_OF`     |
| `BLOCKED_BY`   | `BLOCKS`        |
| `DUPLICATE_OF` | `DUPLICATED_BY` |
| `CAUSED_BY`    | `CAUSES`        |
| `RELATES_TO`   | `RELATES_TO`    |

## List the tickets linked to a ticket

> Returns the tickets linked to this one, each with the link type as seen \*\*from this ticket\*\*.\
> \
> \*\*Filterable\*\* — \`id\`, \`sourceTicketId\`, \`targetTicketId\`, \`relationType\`, \`creatorId\`, \`createdAt\`.\
> \
> \*\*Sortable\*\* — \`id\`, \`createdAt\`.\
> \
> \*\*Searchable\*\* — nothing yet.<br>

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"tags":[{"description":"A **ticket link** connects two tickets and says how they relate. Links are directional and are always\nread from the perspective of the ticket in the path: linking A to B as `BLOCKS` means B shows the\nlink as `BLOCKED_BY`.\n\n| Link | Counterpart |\n| --- | --- |\n| `SUBTASK_OF` | `PARENT_OF` |\n| `BLOCKED_BY` | `BLOCKS` |\n| `DUPLICATE_OF` | `DUPLICATED_BY` |\n| `CAUSED_BY` | `CAUSES` |\n| `RELATES_TO` | `RELATES_TO` |\n","name":"ticket_link"}],"servers":[{"description":"The host serving this document","url":"/api"}],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"description":"Token issued by the central equipme authentication, sent as `Bearer <token>`.","scheme":"bearer","type":"http"},"ApiKeyAuth":{"description":"Static key for machine-to-machine access. Alternative to BearerAuth.","in":"header","name":"X-API-Key","type":"apiKey"}},"schemas":{"v1.ListTicketLinksResponse-domain_TicketLinkView":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.TicketLinkView"},"type":"array","uniqueItems":false}},"type":"object"},"domain.TicketLinkView":{"properties":{"createdAt":{"type":"string"},"creator":{"$ref":"#/components/schemas/domain.Contact"},"relatedTicket":{"$ref":"#/components/schemas/domain.Ticket"},"type":{"$ref":"#/components/schemas/domain.TicketLinkType"}},"type":"object"},"domain.Contact":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext drive automated ticket routing. Set today only on\nGROUP-kind contacts via the group endpoints; nil/empty on ordinary contacts.","type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"email":{"type":"string"},"firstName":{"type":"string"},"id":{"type":"integer"},"kind":{"$ref":"#/components/schemas/domain.ContactKind"},"lastName":{"type":"string"},"mobile":{"type":"string"},"phone":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"},"title":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.ContactKind":{"enum":["","PERSON","INTAKE","GROUP"],"type":"string"},"domain.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"},"domain.Ticket":{"properties":{"agent":{"$ref":"#/components/schemas/domain.Contact"},"agentId":{"type":"integer"},"assignee":{"$ref":"#/components/schemas/domain.Contact"},"assigneeId":{"type":"integer"},"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"integer"},"impact":{"$ref":"#/components/schemas/domain.TicketImpact"},"impactName":{"type":"string"},"labels":{"items":{"$ref":"#/components/schemas/domain.Label"},"type":"array","uniqueItems":false},"opener":{"$ref":"#/components/schemas/domain.Contact"},"openerId":{"type":"integer"},"priority":{"$ref":"#/components/schemas/domain.TicketPriority"},"priorityName":{"type":"string"},"status":{"$ref":"#/components/schemas/domain.TicketStatus"},"statusName":{"type":"string"},"subject":{"type":"string"},"summary":{"type":"string"},"thread":{"$ref":"#/components/schemas/domain.Thread"},"threadId":{"type":"integer"},"type":{"$ref":"#/components/schemas/domain.TicketType"},"typeName":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"urgency":{"$ref":"#/components/schemas/domain.TicketUrgency"},"urgencyName":{"type":"string"}},"type":"object"},"domain.TicketImpact":{"properties":{"color":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"displayName":{"type":"string"},"level":{"type":"integer"},"name":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.Label":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext gate AI label classification: a label is a candidate only\nwhen AutoAssign is on, and then AssignmentContext must be non-empty. Description stays\nhuman-facing — the model reads AssignmentContext.","type":"boolean"},"color":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"id":{"type":"integer"},"name":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.TicketPriority":{"properties":{"color":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"displayName":{"type":"string"},"level":{"type":"integer"},"name":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.TicketStatus":{"properties":{"allowedSourceStatuses":{"items":{"$ref":"#/components/schemas/domain.TicketStatus"},"type":"array","uniqueItems":false},"allowedTargetStatuses":{"items":{"$ref":"#/components/schemas/domain.TicketStatus"},"type":"array","uniqueItems":false},"color":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"displayName":{"type":"string"},"isDefault":{"type":"boolean"},"name":{"type":"string"},"position":{"type":"integer"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.Thread":{"properties":{"attachments":{"items":{"$ref":"#/components/schemas/domain.Attachment"},"type":"array","uniqueItems":false},"channel":{"$ref":"#/components/schemas/domain.Channel"},"channelId":{"type":"integer"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"externalId":{"type":"string"},"id":{"type":"integer"},"messages":{"items":{"$ref":"#/components/schemas/domain.Message"},"type":"array","uniqueItems":false},"parent":{"$ref":"#/components/schemas/domain.Thread"},"parentId":{"type":"integer"},"participants":{"items":{"$ref":"#/components/schemas/domain.Contact"},"type":"array","uniqueItems":false},"status":{"$ref":"#/components/schemas/domain.ThreadStatus"},"subject":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.Attachment":{"properties":{"composing":{"description":"Composing marks the attachment as belonging to an active message composition session.\nThe term mirrors the \"compose\" state in messaging clients: the user is writing a message but has not sent it yet.\nOnce the message is sent, ClaimAttachments links these attachments to it and clears this flag.\nComposing attachments are excluded from all list queries and are eligible for periodic cleanup if never claimed.","type":"boolean"},"contentId":{"description":"ContentID is the MIME Content-ID value used in cid: URI references within the message body.","type":"string"},"contentType":{"type":"string"},"createdAt":{"type":"string"},"creator":{"$ref":"#/components/schemas/domain.Contact"},"creatorId":{"type":"integer"},"id":{"type":"integer"},"inline":{"description":"Inline indicates that the attachment is meant to be displayed within the message content rather than as a separate downloadable file.","type":"boolean"},"link":{"description":"Link refers to the download URL for the attachment. Relative path for the API endpoint that requires authorization,\nnot a pre-signed URL or direct S3 link. This is generated on the fly and not stored in the DB.","type":"string"},"messageId":{"type":"integer"},"name":{"type":"string"},"size":{"type":"number"},"threadId":{"description":"An attachment is listed under the thread or message it belongs to, so the two\nways back are redundant there and close both cycles in the schema. The ids\nidentify them; selecting the relations still works.","type":"integer"}},"type":"object"},"domain.Channel":{"properties":{"active":{"type":"boolean"},"createdAt":{"type":"string"},"id":{"type":"integer"},"kind":{"$ref":"#/components/schemas/domain.ChannelKind"},"name":{"type":"string"},"purpose":{"$ref":"#/components/schemas/domain.ChannelPurpose"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"},"updatedAt":{"type":"string"}},"type":"object"},"domain.ChannelKind":{"enum":["","EMAIL","WEBHOOK","TEAMS","SMS","WHATSAPP","WEBCHAT","NOTICE"],"type":"string"},"domain.ChannelPurpose":{"enum":["","THREAD","TICKET","NOTIFICATION"],"type":"string"},"domain.Message":{"properties":{"attachments":{"items":{"$ref":"#/components/schemas/domain.Attachment"},"type":"array","uniqueItems":false},"author":{"$ref":"#/components/schemas/domain.Contact"},"authorId":{"type":"integer"},"content":{"type":"string"},"contentPreview":{"type":"string"},"contentType":{"type":"string"},"createdAt":{"type":"string"},"direction":{"$ref":"#/components/schemas/domain.MessageDirection"},"id":{"type":"integer"},"originChannel":{"$ref":"#/components/schemas/domain.Channel"},"originChannelId":{"type":"integer"},"replyTo":{"$ref":"#/components/schemas/domain.Message"},"replyToId":{"type":"integer"},"threadId":{"description":"A message is only ever listed under its thread, so the way back is redundant\nthere and closes the thread→message→thread cycle in the schema. threadId\nidentifies it; \"?fields=thread\" still works.","type":"integer"},"updatedAt":{"type":"string"}},"type":"object"},"domain.MessageDirection":{"enum":["INTERNAL","INBOUND","OUTBOUND"],"type":"string"},"domain.ThreadStatus":{"enum":["","OPEN","CLOSED"],"type":"string"},"domain.TicketType":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext gate AI ticket-type classification, mirroring DisplayName.\nRead-only today: ticket types are seeded and have no create/patch surface yet, so both\nstay at their defaults until that surface lands.","type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"displayName":{"type":"string"},"name":{"type":"string"},"position":{"type":"integer"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.TicketUrgency":{"properties":{"color":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"displayName":{"type":"string"},"level":{"type":"integer"},"name":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.TicketLinkType":{"enum":["","SUBTASK_OF","PARENT_OF","BLOCKED_BY","BLOCKS","DUPLICATE_OF","DUPLICATED_BY","CAUSED_BY","CAUSES","RELATES_TO"],"type":"string"},"middleware.ErrorResponse":{"properties":{"error":{"$ref":"#/components/schemas/middleware.ErrorBody"}},"type":"object"},"middleware.ErrorBody":{"properties":{"code":{"description":"Code is the stable, machine-readable reason. Clients match on this, not on the message.","type":"string"},"details":{"description":"Details carries structured context where an error has any — a conflict names what it\ncollided with. Absent otherwise."},"message":{"type":"string"}},"type":"object"}}},"paths":{"/v1/tickets/{ticketId}/links":{"get":{"description":"Returns the tickets linked to this one, each with the link type as seen **from this ticket**.\n\n**Filterable** — `id`, `sourceTicketId`, `targetTicketId`, `relationType`, `creatorId`, `createdAt`.\n\n**Sortable** — `id`, `createdAt`.\n\n**Searchable** — nothing yet.\n","operationId":"listTicketLinks","parameters":[{"description":"Ticket id","in":"path","name":"ticketId","required":true,"schema":{"type":"integer"}},{"description":"JSON filter expression","in":"query","name":"filter","schema":{"type":"string"}},{"description":"Free-text term — no effect here","in":"query","name":"search","schema":{"type":"string"}},{"description":"Comma-separated field:direction terms","in":"query","name":"sort","schema":{"type":"string"}},{"description":"Selection of fields and relations","in":"query","name":"fields","schema":{"type":"string"}},{"description":"Number of entries to skip","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"Page size, 1 to 100","in":"query","name":"limit","schema":{"default":100,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.ListTicketLinksResponse-domain_TicketLinkView"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Not Found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Internal Server Error"}},"summary":"List the tickets linked to a ticket","tags":["ticket_link"]}}}}
```

## Link tickets

> Links this ticket to others. Each entry names the \`ticketId\` to link and the \`type\` as seen from the\
> ticket in the path — the counterpart is recorded automatically for the other side.\
> \
> A ticket cannot be linked to itself; that is answered with \`400\`. Linking a pair that is already\
> linked does not duplicate the link.<br>

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"tags":[{"description":"A **ticket link** connects two tickets and says how they relate. Links are directional and are always\nread from the perspective of the ticket in the path: linking A to B as `BLOCKS` means B shows the\nlink as `BLOCKED_BY`.\n\n| Link | Counterpart |\n| --- | --- |\n| `SUBTASK_OF` | `PARENT_OF` |\n| `BLOCKED_BY` | `BLOCKS` |\n| `DUPLICATE_OF` | `DUPLICATED_BY` |\n| `CAUSED_BY` | `CAUSES` |\n| `RELATES_TO` | `RELATES_TO` |\n","name":"ticket_link"}],"servers":[{"description":"The host serving this document","url":"/api"}],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"description":"Token issued by the central equipme authentication, sent as `Bearer <token>`.","scheme":"bearer","type":"http"},"ApiKeyAuth":{"description":"Static key for machine-to-machine access. Alternative to BearerAuth.","in":"header","name":"X-API-Key","type":"apiKey"}},"schemas":{"v1.AddTicketLinksRequest":{"properties":{"links":{"items":{"$ref":"#/components/schemas/v1.AddTicketLinksRequestItem"},"minItems":1,"type":"array","uniqueItems":false}},"required":["links"],"type":"object"},"v1.AddTicketLinksRequestItem":{"properties":{"ticketId":{"type":"integer"},"type":{"$ref":"#/components/schemas/domain.TicketLinkType"}},"required":["ticketId","type"],"type":"object"},"domain.TicketLinkType":{"enum":["","SUBTASK_OF","PARENT_OF","BLOCKED_BY","BLOCKS","DUPLICATE_OF","DUPLICATED_BY","CAUSED_BY","CAUSES","RELATES_TO"],"type":"string"},"v1.AddTicketLinksResponse-domain_TicketLinkView":{"properties":{"data":{"items":{"$ref":"#/components/schemas/domain.TicketLinkView"},"type":"array","uniqueItems":false}},"type":"object"},"domain.TicketLinkView":{"properties":{"createdAt":{"type":"string"},"creator":{"$ref":"#/components/schemas/domain.Contact"},"relatedTicket":{"$ref":"#/components/schemas/domain.Ticket"},"type":{"$ref":"#/components/schemas/domain.TicketLinkType"}},"type":"object"},"domain.Contact":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext drive automated ticket routing. Set today only on\nGROUP-kind contacts via the group endpoints; nil/empty on ordinary contacts.","type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"email":{"type":"string"},"firstName":{"type":"string"},"id":{"type":"integer"},"kind":{"$ref":"#/components/schemas/domain.ContactKind"},"lastName":{"type":"string"},"mobile":{"type":"string"},"phone":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"},"title":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.ContactKind":{"enum":["","PERSON","INTAKE","GROUP"],"type":"string"},"domain.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"},"domain.Ticket":{"properties":{"agent":{"$ref":"#/components/schemas/domain.Contact"},"agentId":{"type":"integer"},"assignee":{"$ref":"#/components/schemas/domain.Contact"},"assigneeId":{"type":"integer"},"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"createdAt":{"format":"date-time","type":"string"},"id":{"type":"integer"},"impact":{"$ref":"#/components/schemas/domain.TicketImpact"},"impactName":{"type":"string"},"labels":{"items":{"$ref":"#/components/schemas/domain.Label"},"type":"array","uniqueItems":false},"opener":{"$ref":"#/components/schemas/domain.Contact"},"openerId":{"type":"integer"},"priority":{"$ref":"#/components/schemas/domain.TicketPriority"},"priorityName":{"type":"string"},"status":{"$ref":"#/components/schemas/domain.TicketStatus"},"statusName":{"type":"string"},"subject":{"type":"string"},"summary":{"type":"string"},"thread":{"$ref":"#/components/schemas/domain.Thread"},"threadId":{"type":"integer"},"type":{"$ref":"#/components/schemas/domain.TicketType"},"typeName":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"},"urgency":{"$ref":"#/components/schemas/domain.TicketUrgency"},"urgencyName":{"type":"string"}},"type":"object"},"domain.TicketImpact":{"properties":{"color":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"displayName":{"type":"string"},"level":{"type":"integer"},"name":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.Label":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext gate AI label classification: a label is a candidate only\nwhen AutoAssign is on, and then AssignmentContext must be non-empty. Description stays\nhuman-facing — the model reads AssignmentContext.","type":"boolean"},"color":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"id":{"type":"integer"},"name":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.TicketPriority":{"properties":{"color":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"displayName":{"type":"string"},"level":{"type":"integer"},"name":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.TicketStatus":{"properties":{"allowedSourceStatuses":{"items":{"$ref":"#/components/schemas/domain.TicketStatus"},"type":"array","uniqueItems":false},"allowedTargetStatuses":{"items":{"$ref":"#/components/schemas/domain.TicketStatus"},"type":"array","uniqueItems":false},"color":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"displayName":{"type":"string"},"isDefault":{"type":"boolean"},"name":{"type":"string"},"position":{"type":"integer"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.Thread":{"properties":{"attachments":{"items":{"$ref":"#/components/schemas/domain.Attachment"},"type":"array","uniqueItems":false},"channel":{"$ref":"#/components/schemas/domain.Channel"},"channelId":{"type":"integer"},"createdAt":{"format":"date-time","type":"string"},"description":{"type":"string"},"externalId":{"type":"string"},"id":{"type":"integer"},"messages":{"items":{"$ref":"#/components/schemas/domain.Message"},"type":"array","uniqueItems":false},"parent":{"$ref":"#/components/schemas/domain.Thread"},"parentId":{"type":"integer"},"participants":{"items":{"$ref":"#/components/schemas/domain.Contact"},"type":"array","uniqueItems":false},"status":{"$ref":"#/components/schemas/domain.ThreadStatus"},"subject":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.Attachment":{"properties":{"composing":{"description":"Composing marks the attachment as belonging to an active message composition session.\nThe term mirrors the \"compose\" state in messaging clients: the user is writing a message but has not sent it yet.\nOnce the message is sent, ClaimAttachments links these attachments to it and clears this flag.\nComposing attachments are excluded from all list queries and are eligible for periodic cleanup if never claimed.","type":"boolean"},"contentId":{"description":"ContentID is the MIME Content-ID value used in cid: URI references within the message body.","type":"string"},"contentType":{"type":"string"},"createdAt":{"type":"string"},"creator":{"$ref":"#/components/schemas/domain.Contact"},"creatorId":{"type":"integer"},"id":{"type":"integer"},"inline":{"description":"Inline indicates that the attachment is meant to be displayed within the message content rather than as a separate downloadable file.","type":"boolean"},"link":{"description":"Link refers to the download URL for the attachment. Relative path for the API endpoint that requires authorization,\nnot a pre-signed URL or direct S3 link. This is generated on the fly and not stored in the DB.","type":"string"},"messageId":{"type":"integer"},"name":{"type":"string"},"size":{"type":"number"},"threadId":{"description":"An attachment is listed under the thread or message it belongs to, so the two\nways back are redundant there and close both cycles in the schema. The ids\nidentify them; selecting the relations still works.","type":"integer"}},"type":"object"},"domain.Channel":{"properties":{"active":{"type":"boolean"},"createdAt":{"type":"string"},"id":{"type":"integer"},"kind":{"$ref":"#/components/schemas/domain.ChannelKind"},"name":{"type":"string"},"purpose":{"$ref":"#/components/schemas/domain.ChannelPurpose"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"},"updatedAt":{"type":"string"}},"type":"object"},"domain.ChannelKind":{"enum":["","EMAIL","WEBHOOK","TEAMS","SMS","WHATSAPP","WEBCHAT","NOTICE"],"type":"string"},"domain.ChannelPurpose":{"enum":["","THREAD","TICKET","NOTIFICATION"],"type":"string"},"domain.Message":{"properties":{"attachments":{"items":{"$ref":"#/components/schemas/domain.Attachment"},"type":"array","uniqueItems":false},"author":{"$ref":"#/components/schemas/domain.Contact"},"authorId":{"type":"integer"},"content":{"type":"string"},"contentPreview":{"type":"string"},"contentType":{"type":"string"},"createdAt":{"type":"string"},"direction":{"$ref":"#/components/schemas/domain.MessageDirection"},"id":{"type":"integer"},"originChannel":{"$ref":"#/components/schemas/domain.Channel"},"originChannelId":{"type":"integer"},"replyTo":{"$ref":"#/components/schemas/domain.Message"},"replyToId":{"type":"integer"},"threadId":{"description":"A message is only ever listed under its thread, so the way back is redundant\nthere and closes the thread→message→thread cycle in the schema. threadId\nidentifies it; \"?fields=thread\" still works.","type":"integer"},"updatedAt":{"type":"string"}},"type":"object"},"domain.MessageDirection":{"enum":["INTERNAL","INBOUND","OUTBOUND"],"type":"string"},"domain.ThreadStatus":{"enum":["","OPEN","CLOSED"],"type":"string"},"domain.TicketType":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext gate AI ticket-type classification, mirroring DisplayName.\nRead-only today: ticket types are seeded and have no create/patch surface yet, so both\nstay at their defaults until that surface lands.","type":"boolean"},"createdAt":{"format":"date-time","type":"string"},"displayName":{"type":"string"},"name":{"type":"string"},"position":{"type":"integer"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"domain.TicketUrgency":{"properties":{"color":{"type":"string"},"createdAt":{"format":"date-time","type":"string"},"displayName":{"type":"string"},"level":{"type":"integer"},"name":{"type":"string"},"updatedAt":{"format":"date-time","type":"string"}},"type":"object"},"middleware.ErrorResponse":{"properties":{"error":{"$ref":"#/components/schemas/middleware.ErrorBody"}},"type":"object"},"middleware.ErrorBody":{"properties":{"code":{"description":"Code is the stable, machine-readable reason. Clients match on this, not on the message.","type":"string"},"details":{"description":"Details carries structured context where an error has any — a conflict names what it\ncollided with. Absent otherwise."},"message":{"type":"string"}},"type":"object"}}},"paths":{"/v1/tickets/{ticketId}/links":{"post":{"description":"Links this ticket to others. Each entry names the `ticketId` to link and the `type` as seen from the\nticket in the path — the counterpart is recorded automatically for the other side.\n\nA ticket cannot be linked to itself; that is answered with `400`. Linking a pair that is already\nlinked does not duplicate the link.\n","operationId":"addTicketLinks","parameters":[{"description":"Ticket id","in":"path","name":"ticketId","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object"},{"$ref":"#/components/schemas/v1.AddTicketLinksRequest","summary":"request","description":"Links to add"}]}}},"description":"Links to add","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/v1.AddTicketLinksResponse-domain_TicketLinkView"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Not Found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Internal Server Error"}},"summary":"Link tickets","tags":["ticket_link"]}}}}
```

## Unlink tickets

> Removes the links between this ticket and the given ones, in whichever direction they were recorded.\
> Ticket ids that are not linked are ignored. Answers with \`204\` and no body.<br>

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"tags":[{"description":"A **ticket link** connects two tickets and says how they relate. Links are directional and are always\nread from the perspective of the ticket in the path: linking A to B as `BLOCKS` means B shows the\nlink as `BLOCKED_BY`.\n\n| Link | Counterpart |\n| --- | --- |\n| `SUBTASK_OF` | `PARENT_OF` |\n| `BLOCKED_BY` | `BLOCKS` |\n| `DUPLICATE_OF` | `DUPLICATED_BY` |\n| `CAUSED_BY` | `CAUSES` |\n| `RELATES_TO` | `RELATES_TO` |\n","name":"ticket_link"}],"servers":[{"description":"The host serving this document","url":"/api"}],"security":[{"BearerAuth":[]},{"ApiKeyAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"description":"Token issued by the central equipme authentication, sent as `Bearer <token>`.","scheme":"bearer","type":"http"},"ApiKeyAuth":{"description":"Static key for machine-to-machine access. Alternative to BearerAuth.","in":"header","name":"X-API-Key","type":"apiKey"}},"schemas":{"v1.RemoveTicketLinksRequest":{"properties":{"ticketIds":{"items":{"type":"integer"},"minItems":1,"type":"array","uniqueItems":false}},"required":["ticketIds"],"type":"object"},"middleware.ErrorResponse":{"properties":{"error":{"$ref":"#/components/schemas/middleware.ErrorBody"}},"type":"object"},"middleware.ErrorBody":{"properties":{"code":{"description":"Code is the stable, machine-readable reason. Clients match on this, not on the message.","type":"string"},"details":{"description":"Details carries structured context where an error has any — a conflict names what it\ncollided with. Absent otherwise."},"message":{"type":"string"}},"type":"object"}}},"paths":{"/v1/tickets/{ticketId}/links":{"delete":{"description":"Removes the links between this ticket and the given ones, in whichever direction they were recorded.\nTicket ids that are not linked are ignored. Answers with `204` and no body.\n","operationId":"removeTicketLinks","parameters":[{"description":"Ticket id","in":"path","name":"ticketId","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object"},{"$ref":"#/components/schemas/v1.RemoveTicketLinksRequest","summary":"request","description":"Tickets to unlink"}]}}},"description":"Tickets to unlink","required":true},"responses":{"204":{"description":"No Content"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Bad Request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Not Found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/middleware.ErrorResponse"}}},"description":"Internal Server Error"}},"summary":"Unlink tickets","tags":["ticket_link"]}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://hub.equipme.io/development/api-reference-app/ticket-link.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
