> 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-solvio-beta/models.md).

# Models

## The domain.Action object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.Action":{"enum":["","create","read","write","manage","assign","close","delete"],"type":"string"}}}}
```

## The domain.Attachment object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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.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"}}}}
```

## The domain.Channel object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The domain.ChannelIdentityDirection object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.ChannelIdentityDirection":{"enum":["","INBOUND","OUTBOUND"],"type":"string"}}}}
```

## The domain.ChannelKind object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.ChannelKind":{"enum":["","EMAIL","WEBHOOK","TEAMS","SMS","WHATSAPP","WEBCHAT","NOTICE"],"type":"string"}}}}
```

## The domain.ChannelPurpose object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.ChannelPurpose":{"enum":["","THREAD","TICKET","NOTIFICATION"],"type":"string"}}}}
```

## The domain.Contact object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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"}}}}
```

## The domain.ContactKind object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.ContactKind":{"enum":["","PERSON","INTAKE","GROUP"],"type":"string"}}}}
```

## The domain.Group object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.Group":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext / ContactID are read-through from the group's\nGROUP-kind Contact (like Email/Phone); they are not stored on the group table.","type":"boolean"},"contactId":{"type":"integer"},"description":{"type":"string"},"email":{"type":"string"},"id":{"type":"integer"},"members":{"items":{"$ref":"#/components/schemas/domain.GroupMember"},"type":"array","uniqueItems":false},"name":{"type":"string"},"phone":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"}},"type":"object"},"domain.GroupMember":{"properties":{"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"group":{"$ref":"#/components/schemas/domain.Group"},"groupId":{"description":"The composite PK (groupId, contactId) is the by-id analogue for this join\ntable: both key columns are filter+sort (the codegen sort-minimum + what a\nby-key Query(And(Eq,Eq)).Get needs). role reproduces the old GroupMemberFilter.Role.","type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"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.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The domain.GroupMember object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.GroupMember":{"properties":{"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"group":{"$ref":"#/components/schemas/domain.Group"},"groupId":{"description":"The composite PK (groupId, contactId) is the by-id analogue for this join\ntable: both key columns are filter+sort (the codegen sort-minimum + what a\nby-key Query(And(Eq,Eq)).Get needs). role reproduces the old GroupMemberFilter.Role.","type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"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.Group":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext / ContactID are read-through from the group's\nGROUP-kind Contact (like Email/Phone); they are not stored on the group table.","type":"boolean"},"contactId":{"type":"integer"},"description":{"type":"string"},"email":{"type":"string"},"id":{"type":"integer"},"members":{"items":{"$ref":"#/components/schemas/domain.GroupMember"},"type":"array","uniqueItems":false},"name":{"type":"string"},"phone":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"}},"type":"object"},"domain.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The domain.GroupMemberRole object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The domain.IdentityType object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.IdentityType":{"enum":["","EMAIL","PHONE","TOKEN","URL"],"type":"string"}}}}
```

## The domain.Key object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.Key":{"properties":{"actor":{"$ref":"#/components/schemas/domain.User"},"actorId":{"type":"integer"},"createdAt":{"type":"string"},"creator":{"$ref":"#/components/schemas/domain.User"},"creatorId":{"type":"integer"},"expiresAt":{"type":"string"},"id":{"type":"integer"},"ident":{"type":"string"},"label":{"type":"string"},"revokedAt":{"type":"string"},"scopes":{"items":{"$ref":"#/components/schemas/domain.KeyScope"},"type":"array","uniqueItems":false},"usedAt":{"type":"string"}},"type":"object"},"domain.User":{"properties":{"contacts":{"items":{"$ref":"#/components/schemas/domain.Contact"},"type":"array","uniqueItems":false},"id":{"description":"id is the only queryable field — User is an internal/identity entity with no\nuser-facing scoped list; its reads are by-id (Query) or bespoke (identity/contact).","type":"integer"},"realm":{"type":"string"},"sub":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"},"tenantRole":{"$ref":"#/components/schemas/domain.TenantRole"},"username":{"type":"string"}},"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.TenantRole":{"enum":["","ADMIN","MEMBER"],"type":"string"},"domain.KeyScope":{"enum":["","INHERIT"],"type":"string"}}}}
```

## The domain.KeyScope object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.KeyScope":{"enum":["","INHERIT"],"type":"string"}}}}
```

## The domain.Label object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The domain.Message object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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.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.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.MessageDirection":{"enum":["INTERNAL","INBOUND","OUTBOUND"],"type":"string"},"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"}}}}
```

## The domain.MessageAddresseeRole object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.MessageAddresseeRole":{"enum":["","DIRECT","COPIED"],"type":"string"}}}}
```

## The domain.MessageDirection object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.MessageDirection":{"enum":["INTERNAL","INBOUND","OUTBOUND"],"type":"string"}}}}
```

## The domain.Tenant object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The domain.TenantRole object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.TenantRole":{"enum":["","ADMIN","MEMBER"],"type":"string"}}}}
```

## The domain.Thread object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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},"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.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.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"}}}}
```

## The domain.ThreadLinkType object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.ThreadLinkType":{"enum":["","DISCUSSES","DISCUSSED_IN","RELATES_TO"],"type":"string"}}}}
```

## The domain.ThreadLinkView object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.ThreadLinkView":{"properties":{"createdAt":{"type":"string"},"creator":{"$ref":"#/components/schemas/domain.Contact"},"relatedThread":{"$ref":"#/components/schemas/domain.Thread"},"type":{"$ref":"#/components/schemas/domain.ThreadLinkType"}},"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.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},"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.ThreadLinkType":{"enum":["","DISCUSSES","DISCUSSED_IN","RELATES_TO"],"type":"string"}}}}
```

## The domain.ThreadParticipant object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.ThreadParticipant":{"properties":{"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"role":{"$ref":"#/components/schemas/domain.ThreadParticipantRole"},"thread":{"$ref":"#/components/schemas/domain.Thread"},"threadId":{"description":"The composite PK (threadId, contactId) is the by-id analogue for this join\ntable: both key columns are filter+sort (the codegen sort-minimum + what a\nby-key Query(And(Eq,Eq)).Get needs). The old ThreadParticipantFilter had no\nrole axis, so role stays untagged.","type":"integer"}},"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.ThreadParticipantRole":{"enum":["","OWNER","CONTRIBUTOR","OBSERVER"],"type":"string"},"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},"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"}}}}
```

## The domain.ThreadParticipantRole object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.ThreadParticipantRole":{"enum":["","OWNER","CONTRIBUTOR","OBSERVER"],"type":"string"}}}}
```

## The domain.ThreadStatus object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.ThreadStatus":{"enum":["","OPEN","CLOSED"],"type":"string"}}}}
```

## The domain.Ticket object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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.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.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},"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"}}}}
```

## The domain.TicketImpact object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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"}}}}
```

## The domain.TicketLinkType object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.TicketLinkType":{"enum":["","SUBTASK_OF","PARENT_OF","BLOCKED_BY","BLOCKS","DUPLICATE_OF","DUPLICATED_BY","CAUSED_BY","CAUSES","RELATES_TO"],"type":"string"}}}}
```

## The domain.TicketLinkView object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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},"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"}}}}
```

## The domain.TicketPriority object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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"}}}}
```

## The domain.TicketStatus object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The domain.TicketStatusTransition object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.TicketStatusTransition":{"properties":{"role":{"type":"string"},"sourceStatus":{"$ref":"#/components/schemas/domain.TicketStatus"},"targetStatus":{"$ref":"#/components/schemas/domain.TicketStatus"}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The domain.TicketType object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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"}}}}
```

## The domain.TicketUrgency object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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"}}}}
```

## The domain.User object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"domain.User":{"properties":{"contacts":{"items":{"$ref":"#/components/schemas/domain.Contact"},"type":"array","uniqueItems":false},"id":{"description":"id is the only queryable field — User is an internal/identity entity with no\nuser-facing scoped list; its reads are by-id (Query) or bespoke (identity/contact).","type":"integer"},"realm":{"type":"string"},"sub":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"},"tenantRole":{"$ref":"#/components/schemas/domain.TenantRole"},"username":{"type":"string"}},"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.TenantRole":{"enum":["","ADMIN","MEMBER"],"type":"string"}}}}
```

## The middleware.ErrorBody object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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"}}}}
```

## The middleware.ErrorResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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"}}}}
```

## The usecase.Me object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"usecase.Me":{"properties":{"email":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"tenantId":{"type":"integer"},"userId":{"type":"integer"},"username":{"type":"string"}},"type":"object"}}}}
```

## The v1.AddChannelIdentityRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddChannelIdentityRequest":{"properties":{"direction":{"$ref":"#/components/schemas/domain.ChannelIdentityDirection"},"type":{"$ref":"#/components/schemas/domain.IdentityType"},"value":{"type":"string"}},"required":["direction","type","value"],"type":"object"},"domain.ChannelIdentityDirection":{"enum":["","INBOUND","OUTBOUND"],"type":"string"},"domain.IdentityType":{"enum":["","EMAIL","PHONE","TOKEN","URL"],"type":"string"}}}}
```

## The v1.AddChannelIdentityResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddChannelIdentityResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Channel"}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.AddChannelRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddChannelRequest":{"properties":{"active":{"type":"boolean"},"config":{"items":{"type":"integer"},"type":"array","uniqueItems":false},"kind":{"$ref":"#/components/schemas/domain.ChannelKind"},"name":{"type":"string"},"purpose":{"$ref":"#/components/schemas/domain.ChannelPurpose"}},"required":["kind","name","purpose"],"type":"object"},"domain.ChannelKind":{"enum":["","EMAIL","WEBHOOK","TEAMS","SMS","WHATSAPP","WEBCHAT","NOTICE"],"type":"string"},"domain.ChannelPurpose":{"enum":["","THREAD","TICKET","NOTIFICATION"],"type":"string"}}}}
```

## The v1.AddChannelResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddChannelResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Channel"}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.AddContactRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddContactRequest":{"properties":{"description":{"type":"string"},"email":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"mobile":{"type":"string"},"phone":{"type":"string"},"title":{"type":"string"}},"type":"object"}}}}
```

## The v1.AddContactResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddContactResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Contact"}},"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"}}}}
```

## The v1.AddGroupMembersRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddGroupMembersRequest":{"properties":{"members":{"items":{"$ref":"#/components/schemas/v1.AddGroupMembersRequestItem"},"minItems":1,"type":"array","uniqueItems":false}},"required":["members"],"type":"object"},"v1.AddGroupMembersRequestItem":{"properties":{"contactId":{"type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"required":["contactId","role"],"type":"object"},"domain.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The v1.AddGroupMembersRequestItem object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddGroupMembersRequestItem":{"properties":{"contactId":{"type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"required":["contactId","role"],"type":"object"},"domain.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The v1.AddGroupMembersResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddGroupMembersResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/domain.GroupMember"},"type":"array","uniqueItems":false}},"type":"object"},"domain.GroupMember":{"properties":{"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"group":{"$ref":"#/components/schemas/domain.Group"},"groupId":{"description":"The composite PK (groupId, contactId) is the by-id analogue for this join\ntable: both key columns are filter+sort (the codegen sort-minimum + what a\nby-key Query(And(Eq,Eq)).Get needs). role reproduces the old GroupMemberFilter.Role.","type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"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.Group":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext / ContactID are read-through from the group's\nGROUP-kind Contact (like Email/Phone); they are not stored on the group table.","type":"boolean"},"contactId":{"type":"integer"},"description":{"type":"string"},"email":{"type":"string"},"id":{"type":"integer"},"members":{"items":{"$ref":"#/components/schemas/domain.GroupMember"},"type":"array","uniqueItems":false},"name":{"type":"string"},"phone":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"}},"type":"object"},"domain.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The v1.AddGroupRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddGroupRequest":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"type":"boolean"},"description":{"type":"string"},"email":{"type":"string"},"name":{"type":"string"},"phone":{"type":"string"}},"type":"object"}}}}
```

## The v1.AddGroupResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddGroupResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Group"}},"type":"object"},"domain.Group":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext / ContactID are read-through from the group's\nGROUP-kind Contact (like Email/Phone); they are not stored on the group table.","type":"boolean"},"contactId":{"type":"integer"},"description":{"type":"string"},"email":{"type":"string"},"id":{"type":"integer"},"members":{"items":{"$ref":"#/components/schemas/domain.GroupMember"},"type":"array","uniqueItems":false},"name":{"type":"string"},"phone":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"}},"type":"object"},"domain.GroupMember":{"properties":{"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"group":{"$ref":"#/components/schemas/domain.Group"},"groupId":{"description":"The composite PK (groupId, contactId) is the by-id analogue for this join\ntable: both key columns are filter+sort (the codegen sort-minimum + what a\nby-key Query(And(Eq,Eq)).Get needs). role reproduces the old GroupMemberFilter.Role.","type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"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.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The v1.AddKeyRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddKeyRequest":{"properties":{"expiresAt":{"format":"date-time","type":"string"},"label":{"type":"string"}},"required":["label"],"type":"object"}}}}
```

## The v1.AddKeyResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddKeyResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Key"},"secret":{"type":"string"}},"type":"object"},"domain.Key":{"properties":{"actor":{"$ref":"#/components/schemas/domain.User"},"actorId":{"type":"integer"},"createdAt":{"type":"string"},"creator":{"$ref":"#/components/schemas/domain.User"},"creatorId":{"type":"integer"},"expiresAt":{"type":"string"},"id":{"type":"integer"},"ident":{"type":"string"},"label":{"type":"string"},"revokedAt":{"type":"string"},"scopes":{"items":{"$ref":"#/components/schemas/domain.KeyScope"},"type":"array","uniqueItems":false},"usedAt":{"type":"string"}},"type":"object"},"domain.User":{"properties":{"contacts":{"items":{"$ref":"#/components/schemas/domain.Contact"},"type":"array","uniqueItems":false},"id":{"description":"id is the only queryable field — User is an internal/identity entity with no\nuser-facing scoped list; its reads are by-id (Query) or bespoke (identity/contact).","type":"integer"},"realm":{"type":"string"},"sub":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"},"tenantRole":{"$ref":"#/components/schemas/domain.TenantRole"},"username":{"type":"string"}},"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.TenantRole":{"enum":["","ADMIN","MEMBER"],"type":"string"},"domain.KeyScope":{"enum":["","INHERIT"],"type":"string"}}}}
```

## The v1.AddLabelsRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddLabelsRequest":{"properties":{"labels":{"items":{"$ref":"#/components/schemas/v1.AddLabelsRequestItem"},"minItems":1,"type":"array","uniqueItems":false}},"required":["labels"],"type":"object"},"v1.AddLabelsRequestItem":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"type":"boolean"},"color":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"}},"required":["name"],"type":"object"}}}}
```

## The v1.AddLabelsRequestItem object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddLabelsRequestItem":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"type":"boolean"},"color":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"}},"required":["name"],"type":"object"}}}}
```

## The v1.AddLabelsResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddLabelsResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/domain.Label"},"type":"array","uniqueItems":false}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.AddThreadLinksRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddThreadLinksRequest":{"properties":{"links":{"items":{"$ref":"#/components/schemas/v1.AddThreadLinksRequestItem"},"minItems":1,"type":"array","uniqueItems":false}},"required":["links"],"type":"object"},"v1.AddThreadLinksRequestItem":{"properties":{"threadId":{"type":"integer"},"type":{"$ref":"#/components/schemas/domain.ThreadLinkType"}},"required":["threadId","type"],"type":"object"},"domain.ThreadLinkType":{"enum":["","DISCUSSES","DISCUSSED_IN","RELATES_TO"],"type":"string"}}}}
```

## The v1.AddThreadLinksRequestItem object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddThreadLinksRequestItem":{"properties":{"threadId":{"type":"integer"},"type":{"$ref":"#/components/schemas/domain.ThreadLinkType"}},"required":["threadId","type"],"type":"object"},"domain.ThreadLinkType":{"enum":["","DISCUSSES","DISCUSSED_IN","RELATES_TO"],"type":"string"}}}}
```

## The v1.AddThreadLinksResponse-domain\_ThreadLinkView object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddThreadLinksResponse-domain_ThreadLinkView":{"properties":{"data":{"items":{"$ref":"#/components/schemas/domain.ThreadLinkView"},"type":"array","uniqueItems":false}},"type":"object"},"domain.ThreadLinkView":{"properties":{"createdAt":{"type":"string"},"creator":{"$ref":"#/components/schemas/domain.Contact"},"relatedThread":{"$ref":"#/components/schemas/domain.Thread"},"type":{"$ref":"#/components/schemas/domain.ThreadLinkType"}},"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.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},"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.ThreadLinkType":{"enum":["","DISCUSSES","DISCUSSED_IN","RELATES_TO"],"type":"string"}}}}
```

## The v1.AddThreadMessageAddressee object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddThreadMessageAddressee":{"properties":{"contactId":{"type":"integer"},"role":{"$ref":"#/components/schemas/domain.MessageAddresseeRole"}},"required":["contactId","role"],"type":"object"},"domain.MessageAddresseeRole":{"enum":["","DIRECT","COPIED"],"type":"string"}}}}
```

## The v1.AddThreadMessageRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddThreadMessageRequest":{"properties":{"addressees":{"items":{"$ref":"#/components/schemas/v1.AddThreadMessageAddressee"},"type":"array","uniqueItems":false},"attachmentIds":{"items":{"type":"integer"},"type":"array","uniqueItems":false},"content":{"type":"string"},"replyToId":{"type":"integer"}},"required":["content"],"type":"object"},"v1.AddThreadMessageAddressee":{"properties":{"contactId":{"type":"integer"},"role":{"$ref":"#/components/schemas/domain.MessageAddresseeRole"}},"required":["contactId","role"],"type":"object"},"domain.MessageAddresseeRole":{"enum":["","DIRECT","COPIED"],"type":"string"}}}}
```

## The v1.AddThreadMessageResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddThreadMessageResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Message"}},"type":"object"},"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.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.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.MessageDirection":{"enum":["INTERNAL","INBOUND","OUTBOUND"],"type":"string"},"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"}}}}
```

## The v1.AddThreadParticipantsRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddThreadParticipantsRequest":{"properties":{"participants":{"items":{"$ref":"#/components/schemas/v1.AddThreadParticipantsRequestItem"},"minItems":1,"type":"array","uniqueItems":false}},"required":["participants"],"type":"object"},"v1.AddThreadParticipantsRequestItem":{"properties":{"contactId":{"type":"integer"},"role":{"$ref":"#/components/schemas/domain.ThreadParticipantRole"}},"required":["contactId","role"],"type":"object"},"domain.ThreadParticipantRole":{"enum":["","OWNER","CONTRIBUTOR","OBSERVER"],"type":"string"}}}}
```

## The v1.AddThreadParticipantsRequestItem object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddThreadParticipantsRequestItem":{"properties":{"contactId":{"type":"integer"},"role":{"$ref":"#/components/schemas/domain.ThreadParticipantRole"}},"required":["contactId","role"],"type":"object"},"domain.ThreadParticipantRole":{"enum":["","OWNER","CONTRIBUTOR","OBSERVER"],"type":"string"}}}}
```

## The v1.AddThreadParticipantsResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddThreadParticipantsResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/domain.ThreadParticipant"},"type":"array","uniqueItems":false}},"type":"object"},"domain.ThreadParticipant":{"properties":{"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"role":{"$ref":"#/components/schemas/domain.ThreadParticipantRole"},"thread":{"$ref":"#/components/schemas/domain.Thread"},"threadId":{"description":"The composite PK (threadId, contactId) is the by-id analogue for this join\ntable: both key columns are filter+sort (the codegen sort-minimum + what a\nby-key Query(And(Eq,Eq)).Get needs). The old ThreadParticipantFilter had no\nrole axis, so role stays untagged.","type":"integer"}},"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.ThreadParticipantRole":{"enum":["","OWNER","CONTRIBUTOR","OBSERVER"],"type":"string"},"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},"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"}}}}
```

## The v1.AddThreadRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddThreadRequest":{"properties":{"description":{"type":"string"},"links":{"items":{"$ref":"#/components/schemas/v1.AddThreadLinksRequestItem"},"type":"array","uniqueItems":false},"subject":{"type":"string"}},"required":["subject"],"type":"object"},"v1.AddThreadLinksRequestItem":{"properties":{"threadId":{"type":"integer"},"type":{"$ref":"#/components/schemas/domain.ThreadLinkType"}},"required":["threadId","type"],"type":"object"},"domain.ThreadLinkType":{"enum":["","DISCUSSES","DISCUSSED_IN","RELATES_TO"],"type":"string"}}}}
```

## The v1.AddThreadResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddThreadResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Thread"}},"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},"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.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.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"}}}}
```

## The v1.AddTicketLinksRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"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"}}}}
```

## The v1.AddTicketLinksRequestItem object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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"}}}}
```

## The v1.AddTicketLinksResponse-domain\_TicketLinkView object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"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},"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"}}}}
```

## The v1.AddTicketRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddTicketRequest":{"properties":{"agentId":{"type":"integer"},"assigneeId":{"type":"integer"},"channelId":{"type":"integer"},"contactId":{"type":"integer"},"description":{"type":"string"},"subject":{"type":"string"},"threadId":{"type":"integer"},"typeName":{"type":"string"}},"required":["description"],"type":"object"}}}}
```

## The v1.AddTicketResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddTicketResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Ticket"}},"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.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.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},"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"}}}}
```

## The v1.AddTicketStatusRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddTicketStatusRequest":{"properties":{"allowedSourceStatusNames":{"items":{"type":"string"},"type":"array","uniqueItems":false},"allowedTargetStatusNames":{"items":{"type":"string"},"type":"array","uniqueItems":false},"color":{"type":"string"},"displayName":{"type":"string"},"isDefault":{"type":"boolean"},"name":{"type":"string"},"position":{"type":"integer"}},"required":["displayName","name"],"type":"object"}}}}
```

## The v1.AddTicketStatusResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddTicketStatusResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.TicketStatus"}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.AddTicketStatusTransitionRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddTicketStatusTransitionRequest":{"properties":{"role":{"type":"string"},"sourceStatusName":{"type":"string"},"targetStatusName":{"type":"string"}},"required":["sourceStatusName","targetStatusName"],"type":"object"}}}}
```

## The v1.AddTicketStatusTransitionResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.AddTicketStatusTransitionResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.TicketStatusTransition"}},"type":"object"},"domain.TicketStatusTransition":{"properties":{"role":{"type":"string"},"sourceStatus":{"$ref":"#/components/schemas/domain.TicketStatus"},"targetStatus":{"$ref":"#/components/schemas/domain.TicketStatus"}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.CheckPermissionsRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.CheckPermissionsRequest":{"properties":{"requests":{"items":{"$ref":"#/components/schemas/v1.CheckPermissionsRequestItem"},"minItems":1,"type":"array","uniqueItems":false}},"required":["requests"],"type":"object"},"v1.CheckPermissionsRequestItem":{"properties":{"action":{"$ref":"#/components/schemas/domain.Action"},"domain":{"type":"string"},"resource":{"type":"string"}},"required":["action","domain","resource"],"type":"object"},"domain.Action":{"enum":["","create","read","write","manage","assign","close","delete"],"type":"string"}}}}
```

## The v1.CheckPermissionsRequestItem object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.CheckPermissionsRequestItem":{"properties":{"action":{"$ref":"#/components/schemas/domain.Action"},"domain":{"type":"string"},"resource":{"type":"string"}},"required":["action","domain","resource"],"type":"object"},"domain.Action":{"enum":["","create","read","write","manage","assign","close","delete"],"type":"string"}}}}
```

## The v1.CheckPermissionsResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.CheckPermissionsResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/v1.CheckPermissionsResponseItem"},"type":"array","uniqueItems":false}},"type":"object"},"v1.CheckPermissionsResponseItem":{"properties":{"action":{"$ref":"#/components/schemas/domain.Action"},"allowed":{"type":"boolean"},"domain":{"type":"string"},"resource":{"type":"string"}},"type":"object"},"domain.Action":{"enum":["","create","read","write","manage","assign","close","delete"],"type":"string"}}}}
```

## The v1.CheckPermissionsResponseItem object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.CheckPermissionsResponseItem":{"properties":{"action":{"$ref":"#/components/schemas/domain.Action"},"allowed":{"type":"boolean"},"domain":{"type":"string"},"resource":{"type":"string"}},"type":"object"},"domain.Action":{"enum":["","create","read","write","manage","assign","close","delete"],"type":"string"}}}}
```

## The v1.DeleteChannelIdentityResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.DeleteChannelIdentityResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Channel"}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.DeleteTicketStatusRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.DeleteTicketStatusRequest":{"properties":{"migrationTargetName":{"type":"string"}},"type":"object"}}}}
```

## The v1.DeleteTicketStatusTransitionRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.DeleteTicketStatusTransitionRequest":{"properties":{"sourceStatusName":{"type":"string"},"targetStatusName":{"type":"string"}},"required":["sourceStatusName","targetStatusName"],"type":"object"}}}}
```

## The v1.GetChannelResponse-domain\_Channel object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.GetChannelResponse-domain_Channel":{"properties":{"data":{"$ref":"#/components/schemas/domain.Channel"}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.GetContactResponse-domain\_Contact object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.GetContactResponse-domain_Contact":{"properties":{"data":{"$ref":"#/components/schemas/domain.Contact"}},"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"}}}}
```

## The v1.GetGroupResponse-domain\_Group object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.GetGroupResponse-domain_Group":{"properties":{"data":{"$ref":"#/components/schemas/domain.Group"}},"type":"object"},"domain.Group":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext / ContactID are read-through from the group's\nGROUP-kind Contact (like Email/Phone); they are not stored on the group table.","type":"boolean"},"contactId":{"type":"integer"},"description":{"type":"string"},"email":{"type":"string"},"id":{"type":"integer"},"members":{"items":{"$ref":"#/components/schemas/domain.GroupMember"},"type":"array","uniqueItems":false},"name":{"type":"string"},"phone":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"}},"type":"object"},"domain.GroupMember":{"properties":{"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"group":{"$ref":"#/components/schemas/domain.Group"},"groupId":{"description":"The composite PK (groupId, contactId) is the by-id analogue for this join\ntable: both key columns are filter+sort (the codegen sort-minimum + what a\nby-key Query(And(Eq,Eq)).Get needs). role reproduces the old GroupMemberFilter.Role.","type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"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.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The v1.GetLabelResponse-domain\_Label object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.GetLabelResponse-domain_Label":{"properties":{"data":{"$ref":"#/components/schemas/domain.Label"}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.GetMeResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.GetMeResponse":{"properties":{"data":{"$ref":"#/components/schemas/usecase.Me"}},"type":"object"},"usecase.Me":{"properties":{"email":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"tenantId":{"type":"integer"},"userId":{"type":"integer"},"username":{"type":"string"}},"type":"object"}}}}
```

## The v1.GetThreadResponse-domain\_Thread object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.GetThreadResponse-domain_Thread":{"properties":{"data":{"$ref":"#/components/schemas/domain.Thread"}},"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},"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.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.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"}}}}
```

## The v1.GetTicketResponse-domain\_Ticket object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.GetTicketResponse-domain_Ticket":{"properties":{"data":{"$ref":"#/components/schemas/domain.Ticket"}},"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.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.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},"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"}}}}
```

## The v1.ListAttachmentsResponse-domain\_Attachment object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListAttachmentsResponse-domain_Attachment":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.Attachment"},"type":"array","uniqueItems":false}},"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.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"}}}}
```

## The v1.ListChannelsResponse-domain\_Channel object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListChannelsResponse-domain_Channel":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.Channel"},"type":"array","uniqueItems":false}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.ListContactsResponse-domain\_Contact object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListContactsResponse-domain_Contact":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.Contact"},"type":"array","uniqueItems":false}},"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"}}}}
```

## The v1.ListGroupMembersResponse-domain\_GroupMember object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListGroupMembersResponse-domain_GroupMember":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.GroupMember"},"type":"array","uniqueItems":false}},"type":"object"},"domain.GroupMember":{"properties":{"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"group":{"$ref":"#/components/schemas/domain.Group"},"groupId":{"description":"The composite PK (groupId, contactId) is the by-id analogue for this join\ntable: both key columns are filter+sort (the codegen sort-minimum + what a\nby-key Query(And(Eq,Eq)).Get needs). role reproduces the old GroupMemberFilter.Role.","type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"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.Group":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext / ContactID are read-through from the group's\nGROUP-kind Contact (like Email/Phone); they are not stored on the group table.","type":"boolean"},"contactId":{"type":"integer"},"description":{"type":"string"},"email":{"type":"string"},"id":{"type":"integer"},"members":{"items":{"$ref":"#/components/schemas/domain.GroupMember"},"type":"array","uniqueItems":false},"name":{"type":"string"},"phone":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"}},"type":"object"},"domain.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The v1.ListGroupsResponse-domain\_Group object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListGroupsResponse-domain_Group":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.Group"},"type":"array","uniqueItems":false}},"type":"object"},"domain.Group":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext / ContactID are read-through from the group's\nGROUP-kind Contact (like Email/Phone); they are not stored on the group table.","type":"boolean"},"contactId":{"type":"integer"},"description":{"type":"string"},"email":{"type":"string"},"id":{"type":"integer"},"members":{"items":{"$ref":"#/components/schemas/domain.GroupMember"},"type":"array","uniqueItems":false},"name":{"type":"string"},"phone":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"}},"type":"object"},"domain.GroupMember":{"properties":{"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"group":{"$ref":"#/components/schemas/domain.Group"},"groupId":{"description":"The composite PK (groupId, contactId) is the by-id analogue for this join\ntable: both key columns are filter+sort (the codegen sort-minimum + what a\nby-key Query(And(Eq,Eq)).Get needs). role reproduces the old GroupMemberFilter.Role.","type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"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.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The v1.ListKeysResponse-domain\_Key object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListKeysResponse-domain_Key":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.Key"},"type":"array","uniqueItems":false}},"type":"object"},"domain.Key":{"properties":{"actor":{"$ref":"#/components/schemas/domain.User"},"actorId":{"type":"integer"},"createdAt":{"type":"string"},"creator":{"$ref":"#/components/schemas/domain.User"},"creatorId":{"type":"integer"},"expiresAt":{"type":"string"},"id":{"type":"integer"},"ident":{"type":"string"},"label":{"type":"string"},"revokedAt":{"type":"string"},"scopes":{"items":{"$ref":"#/components/schemas/domain.KeyScope"},"type":"array","uniqueItems":false},"usedAt":{"type":"string"}},"type":"object"},"domain.User":{"properties":{"contacts":{"items":{"$ref":"#/components/schemas/domain.Contact"},"type":"array","uniqueItems":false},"id":{"description":"id is the only queryable field — User is an internal/identity entity with no\nuser-facing scoped list; its reads are by-id (Query) or bespoke (identity/contact).","type":"integer"},"realm":{"type":"string"},"sub":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"},"tenantRole":{"$ref":"#/components/schemas/domain.TenantRole"},"username":{"type":"string"}},"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.TenantRole":{"enum":["","ADMIN","MEMBER"],"type":"string"},"domain.KeyScope":{"enum":["","INHERIT"],"type":"string"}}}}
```

## The v1.ListLabelsResponse-domain\_Label object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListLabelsResponse-domain_Label":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.Label"},"type":"array","uniqueItems":false}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.ListThreadLinksResponse-domain\_ThreadLinkView object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListThreadLinksResponse-domain_ThreadLinkView":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.ThreadLinkView"},"type":"array","uniqueItems":false}},"type":"object"},"domain.ThreadLinkView":{"properties":{"createdAt":{"type":"string"},"creator":{"$ref":"#/components/schemas/domain.Contact"},"relatedThread":{"$ref":"#/components/schemas/domain.Thread"},"type":{"$ref":"#/components/schemas/domain.ThreadLinkType"}},"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.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},"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.ThreadLinkType":{"enum":["","DISCUSSES","DISCUSSED_IN","RELATES_TO"],"type":"string"}}}}
```

## The v1.ListThreadMessagesResponse-domain\_Message object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListThreadMessagesResponse-domain_Message":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.Message"},"type":"array","uniqueItems":false}},"type":"object"},"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.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.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.MessageDirection":{"enum":["INTERNAL","INBOUND","OUTBOUND"],"type":"string"},"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"}}}}
```

## The v1.ListThreadParticipantsResponse-domain\_ThreadParticipant object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListThreadParticipantsResponse-domain_ThreadParticipant":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.ThreadParticipant"},"type":"array","uniqueItems":false}},"type":"object"},"domain.ThreadParticipant":{"properties":{"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"role":{"$ref":"#/components/schemas/domain.ThreadParticipantRole"},"thread":{"$ref":"#/components/schemas/domain.Thread"},"threadId":{"description":"The composite PK (threadId, contactId) is the by-id analogue for this join\ntable: both key columns are filter+sort (the codegen sort-minimum + what a\nby-key Query(And(Eq,Eq)).Get needs). The old ThreadParticipantFilter had no\nrole axis, so role stays untagged.","type":"integer"}},"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.ThreadParticipantRole":{"enum":["","OWNER","CONTRIBUTOR","OBSERVER"],"type":"string"},"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},"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"}}}}
```

## The v1.ListThreadsResponse-domain\_Thread object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListThreadsResponse-domain_Thread":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.Thread"},"type":"array","uniqueItems":false}},"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},"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.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.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"}}}}
```

## The v1.ListTicketImpactsResponse-domain\_TicketImpact object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListTicketImpactsResponse-domain_TicketImpact":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.TicketImpact"},"type":"array","uniqueItems":false}},"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"}}}}
```

## The v1.ListTicketLinksResponse-domain\_TicketLinkView object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"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},"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"}}}}
```

## The v1.ListTicketPrioritiesResponse-domain\_TicketPriority object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListTicketPrioritiesResponse-domain_TicketPriority":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.TicketPriority"},"type":"array","uniqueItems":false}},"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"}}}}
```

## The v1.ListTicketStatusTransitionsResponse-domain\_TicketStatusTransition object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListTicketStatusTransitionsResponse-domain_TicketStatusTransition":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.TicketStatusTransition"},"type":"array","uniqueItems":false}},"type":"object"},"domain.TicketStatusTransition":{"properties":{"role":{"type":"string"},"sourceStatus":{"$ref":"#/components/schemas/domain.TicketStatus"},"targetStatus":{"$ref":"#/components/schemas/domain.TicketStatus"}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.ListTicketStatusesResponse-domain\_TicketStatus object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListTicketStatusesResponse-domain_TicketStatus":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.TicketStatus"},"type":"array","uniqueItems":false}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.ListTicketTypesResponse-domain\_TicketType object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListTicketTypesResponse-domain_TicketType":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.TicketType"},"type":"array","uniqueItems":false}},"type":"object"},"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"}}}}
```

## The v1.ListTicketUrgenciesResponse-domain\_TicketUrgency object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListTicketUrgenciesResponse-domain_TicketUrgency":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.TicketUrgency"},"type":"array","uniqueItems":false}},"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"}}}}
```

## The v1.ListTicketsResponse-domain\_Ticket object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.ListTicketsResponse-domain_Ticket":{"properties":{"count":{"type":"integer"},"data":{"items":{"$ref":"#/components/schemas/domain.Ticket"},"type":"array","uniqueItems":false}},"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.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.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},"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"}}}}
```

## The v1.PatchChannelRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchChannelRequest":{"properties":{"active":{"type":"boolean"},"config":{"type":"object"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.PatchChannelResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchChannelResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Channel"}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.PatchContactRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchContactRequest":{"properties":{"description":{"type":"string"},"email":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"mobile":{"type":"string"},"phone":{"type":"string"},"title":{"type":"string"}},"type":"object"}}}}
```

## The v1.PatchContactResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchContactResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Contact"}},"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"}}}}
```

## The v1.PatchGroupMembersRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchGroupMembersRequest":{"properties":{"members":{"items":{"$ref":"#/components/schemas/v1.PatchGroupMembersRequestItem"},"minItems":1,"type":"array","uniqueItems":false}},"required":["members"],"type":"object"},"v1.PatchGroupMembersRequestItem":{"properties":{"contactId":{"type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"required":["contactId","role"],"type":"object"},"domain.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The v1.PatchGroupMembersRequestItem object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchGroupMembersRequestItem":{"properties":{"contactId":{"type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"required":["contactId","role"],"type":"object"},"domain.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The v1.PatchGroupMembersResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchGroupMembersResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/domain.GroupMember"},"type":"array","uniqueItems":false}},"type":"object"},"domain.GroupMember":{"properties":{"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"group":{"$ref":"#/components/schemas/domain.Group"},"groupId":{"description":"The composite PK (groupId, contactId) is the by-id analogue for this join\ntable: both key columns are filter+sort (the codegen sort-minimum + what a\nby-key Query(And(Eq,Eq)).Get needs). role reproduces the old GroupMemberFilter.Role.","type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"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.Group":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext / ContactID are read-through from the group's\nGROUP-kind Contact (like Email/Phone); they are not stored on the group table.","type":"boolean"},"contactId":{"type":"integer"},"description":{"type":"string"},"email":{"type":"string"},"id":{"type":"integer"},"members":{"items":{"$ref":"#/components/schemas/domain.GroupMember"},"type":"array","uniqueItems":false},"name":{"type":"string"},"phone":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"}},"type":"object"},"domain.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The v1.PatchGroupRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchGroupRequest":{"properties":{"description":{"type":"string"},"email":{"type":"string"},"name":{"type":"string"},"phone":{"type":"string"}},"type":"object"}}}}
```

## The v1.PatchGroupResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchGroupResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Group"}},"type":"object"},"domain.Group":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"description":"AutoAssign / AssignmentContext / ContactID are read-through from the group's\nGROUP-kind Contact (like Email/Phone); they are not stored on the group table.","type":"boolean"},"contactId":{"type":"integer"},"description":{"type":"string"},"email":{"type":"string"},"id":{"type":"integer"},"members":{"items":{"$ref":"#/components/schemas/domain.GroupMember"},"type":"array","uniqueItems":false},"name":{"type":"string"},"phone":{"type":"string"},"tenant":{"$ref":"#/components/schemas/domain.Tenant"},"tenantId":{"type":"integer"}},"type":"object"},"domain.GroupMember":{"properties":{"contact":{"$ref":"#/components/schemas/domain.Contact"},"contactId":{"type":"integer"},"group":{"$ref":"#/components/schemas/domain.Group"},"groupId":{"description":"The composite PK (groupId, contactId) is the by-id analogue for this join\ntable: both key columns are filter+sort (the codegen sort-minimum + what a\nby-key Query(And(Eq,Eq)).Get needs). role reproduces the old GroupMemberFilter.Role.","type":"integer"},"role":{"$ref":"#/components/schemas/domain.GroupMemberRole"}},"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.GroupMemberRole":{"enum":["","MEMBER","ADMIN","OBSERVER"],"type":"string"}}}}
```

## The v1.PatchLabelRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchLabelRequest":{"properties":{"assignmentContext":{"type":"string"},"autoAssign":{"type":"boolean"},"color":{"type":"string"},"description":{"type":"string"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.PatchLabelResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchLabelResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Label"}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.PatchThreadMessageRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchThreadMessageRequest":{"properties":{"content":{"type":"string"},"contentType":{"type":"string"}},"type":"object"}}}}
```

## The v1.PatchThreadMessageResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchThreadMessageResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Message"}},"type":"object"},"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.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.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.MessageDirection":{"enum":["INTERNAL","INBOUND","OUTBOUND"],"type":"string"},"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"}}}}
```

## The v1.PatchTicketRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchTicketRequest":{"properties":{"agentId":{"type":"integer"},"assigneeId":{"type":"integer"},"contactId":{"type":"integer"},"impactName":{"type":"string"},"labels":{"items":{"type":"string"},"type":"array","uniqueItems":false},"priorityName":{"type":"string"},"statusName":{"type":"string"},"subject":{"type":"string"},"typeName":{"type":"string"},"urgencyName":{"type":"string"}},"type":"object"}}}}
```

## The v1.PatchTicketResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchTicketResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.Ticket"}},"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.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.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},"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"}}}}
```

## The v1.PatchTicketStatusRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchTicketStatusRequest":{"properties":{"color":{"type":"string"},"displayName":{"type":"string"},"isDefault":{"type":"boolean"},"position":{"type":"integer"}},"type":"object"}}}}
```

## The v1.PatchTicketStatusResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.PatchTicketStatusResponse":{"properties":{"data":{"$ref":"#/components/schemas/domain.TicketStatus"}},"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.Tenant":{"properties":{"id":{"type":"integer"},"name":{"type":"string"}},"type":"object"}}}}
```

## The v1.RemoveGroupMembersRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.RemoveGroupMembersRequest":{"properties":{"members":{"items":{"$ref":"#/components/schemas/v1.RemoveGroupMembersRequestItem"},"minItems":1,"type":"array","uniqueItems":false}},"required":["members"],"type":"object"},"v1.RemoveGroupMembersRequestItem":{"properties":{"contactId":{"type":"integer"}},"required":["contactId"],"type":"object"}}}}
```

## The v1.RemoveGroupMembersRequestItem object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.RemoveGroupMembersRequestItem":{"properties":{"contactId":{"type":"integer"}},"required":["contactId"],"type":"object"}}}}
```

## The v1.RemoveThreadLinksRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.RemoveThreadLinksRequest":{"properties":{"threadIds":{"items":{"type":"integer"},"minItems":1,"type":"array","uniqueItems":false}},"required":["threadIds"],"type":"object"}}}}
```

## The v1.RemoveThreadParticipantsRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.RemoveThreadParticipantsRequest":{"properties":{"participants":{"items":{"$ref":"#/components/schemas/v1.RemoveThreadParticipantsRequestItem"},"minItems":1,"type":"array","uniqueItems":false}},"required":["participants"],"type":"object"},"v1.RemoveThreadParticipantsRequestItem":{"properties":{"contactId":{"type":"integer"}},"required":["contactId"],"type":"object"}}}}
```

## The v1.RemoveThreadParticipantsRequestItem object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.RemoveThreadParticipantsRequestItem":{"properties":{"contactId":{"type":"integer"}},"required":["contactId"],"type":"object"}}}}
```

## The v1.RemoveTicketLinksRequest object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.RemoveTicketLinksRequest":{"properties":{"ticketIds":{"items":{"type":"integer"},"minItems":1,"type":"array","uniqueItems":false}},"required":["ticketIds"],"type":"object"}}}}
```

## The v1.UploadAttachmentsError object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.UploadAttachmentsError":{"properties":{"error":{"type":"string"},"filename":{"type":"string"}},"type":"object"}}}}
```

## The v1.UploadAttachmentsResponse object

```json
{"openapi":"3.1.0","info":{"title":"Solvio REST API","version":"1.0.0-beta"},"components":{"schemas":{"v1.UploadAttachmentsResponse":{"properties":{"data":{"items":{"$ref":"#/components/schemas/domain.Attachment"},"type":"array","uniqueItems":false},"errors":{"items":{"$ref":"#/components/schemas/v1.UploadAttachmentsError"},"type":"array","uniqueItems":false}},"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.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"},"v1.UploadAttachmentsError":{"properties":{"error":{"type":"string"},"filename":{"type":"string"}},"type":"object"}}}}
```


---

# 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-solvio-beta/models.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.
