https://api.atys.pro/api/v1/tickets,
respondem JSON e têm contrato estável: mudanças incompatíveis só entram numa versão nova.
Como funciona
Tudo o que a equipe faz em Tickets na Atys também pode ser feito pela API: abrir chamados a partir do seu sistema, definir prioridade e status, escolher responsáveis, ligar contatos, responder ao cliente ou registrar notas internas e anexar arquivos. Cada chamada passa pelas mesmas regras da plataforma: responsáveis e contatos recebem as notificações e as automações disparam.
Os contatos do ticket são os mesmos da API de Contatos;
use o id de lá em contact_ids.
- Conhecer os catálogos — status, prioridades e os demais ids que o ticket pede.
- Abrir e organizar — criar, listar, editar, status, prioridade, responsáveis, contatos e etiquetas.
- Responder — interações com o contato, notas internas e anexos.
- Portal do contato — o que o contato vê e como ele acompanha o ticket.
Autenticação e permissões
Use uma chave de API com as permissões de Tickets que a integração precisa:
| Permissão da chave | Libera |
|---|---|
| Consultar tickets | Todos os GET: catálogos, tickets, interações e anexos. |
| Criar, editar e responder tickets | Criar e editar tickets, status, prioridade, responsável, atendentes, contatos, etiquetas, fixar e campos do formulário; responder, notas internas, anexos e acesso do contato. |
Tickets: como funcionam
Um ticket é um chamado de atendimento com assunto, status, prioridade, categoria, um atendente responsável, os atendentes que participam, os contatos envolvidos e etiquetas. Cada ação desta seção faz o mesmo que o item correspondente da aba Tickets da Atys: abrir um ticket envia os e-mails de novo ticket aos atendentes, ao criador e aos contatos, e mudar o status dispara as integrações ligadas ao ticket (como o ClickUp).
- Visibilidade: como na tela, todo ticket da empresa é visível para quem tem acesso ao módulo de Atendimento, inclusive para a chave de API. Ticket de outra empresa responde
404. - Permissões: as mesmas da plataforma. Abrir pede criar tickets. Editar assunto, categoria, status, prioridade, atendentes, contatos e etiquetas pede editar tickets. Atribuir o ticket a outra pessoa pede atribuir tickets. Sem a permissão,
403 forbidden. - Dados do contato: nome e e-mail dos contatos seguem as permissões do usuário API. Sem ver nome completo aparece só o primeiro nome, e sem ver e-mail aparece só o domínio.
- Por usuário:
is_pinnedeunread_countse referem ao usuário autenticado (o usuário API da chave), como na tela.
| Campo | Descrição |
|---|---|
status | id, name (código interno), label (o texto da tela) e group: open (aberto), paused (pausado) ou finished (finalizado). Veja o catálogo. |
priority | Prioridade do ticket, ou null. |
category | Categoria com o setor a que ela pertence (o "Ambiente" da tela), ou null. |
responsible_user | O atendente responsável. Na criação é quem abriu o ticket; muda com atribuir. |
users | Os atendentes que participam do ticket. Eles recebem os e-mails e têm o contador de interações não lidas. |
contacts | Contatos do ticket (ids da API de Contatos). Eles acompanham o ticket pelo portal e recebem os e-mails. |
tags | Etiquetas de ticket. |
is_pinned | Fixado pelo usuário autenticado. |
unread_count | Interações ainda não lidas pelo usuário autenticado. É 0 se ele não for atendente do ticket. |
interactions_count / last_interaction_at | Quantas interações o ticket tem e quando foi a última. O histórico fica nas interações. |
Status (catálogo)
Os 15 status de ticket, com o grupo de cada um. settable: true marca os que
alterar status aceita, que são as opções do menu "Atualizar status" da
tela. Não atribuído e Atribuído não entram nessa lista porque vêm da criação e da
atribuição. Agendado, Em mudança / deploy e
Arquivado também ficam de fora, porque a tela não os oferece.
| Grupo | Status (id — rótulo) |
|---|---|
open | 16 Não atribuído · 17 Atribuído · 18 Em processamento · 19 Reaberto |
paused | 20 Aguardando cliente · 21 Aguardando terceiro · 22 Agendado · 23 Em mudança / deploy · 24 Bloqueado internamente |
finished | 25 Resolvido · 26 Cancelado pelo cliente · 27 Sem solução · 28 Limitação conhecida · 29 Spam / Indevido · 30 Arquivado |
Exemplos de código — listar status de ticket
curl "https://api.atys.pro/api/v1/tickets/statuses" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/statuses', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/statuses',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/statuses');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/statuses', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/statuses", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 16,
"name": "TICKETS_OPENED_UNASSIGNED",
"label": "Não atribuído",
"group": "open",
"settable": false
},
{
"id": 18,
"name": "TICKETS_OPENED_PROCESSING",
"label": "Em processamento",
"group": "open",
"settable": true
},
{
"id": 25,
"name": "TICKETS_FINISHED_RESOLVED",
"label": "Resolvido",
"group": "finished",
"settable": true
}
]
}
Prioridades (catálogo)
As prioridades são as mesmas da plataforma inteira (iguais às do CRM): 1 Alta, 2 Média e 3 Baixa.
Exemplos de código — listar prioridades
curl "https://api.atys.pro/api/v1/tickets/priorities" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/priorities', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/priorities',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/priorities');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/priorities', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/priorities", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 1,
"name": "Alta",
"description": "Prioridade alta"
},
{
"id": 2,
"name": "Média",
"description": "Prioridade média"
},
{
"id": 3,
"name": "Baixa",
"description": "Prioridade baixa"
}
]
}
Categorias (catálogo)
As categorias de ticket da empresa, cada uma com o setor a que pertence. No formulário da tela, o setor serve para filtrar as categorias. O que fica gravado no ticket é a categoria, e o setor vem junto com ela.
Exemplos de código — listar categorias de ticket
curl "https://api.atys.pro/api/v1/tickets/categories" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/categories', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/categories',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/categories');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/categories', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/categories", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 7,
"name": "Financeiro",
"description": "Boletos, notas e cobranças",
"sector": {
"id": 6,
"name": "Suporte"
}
}
]
}
Etiquetas de ticket (catálogo)
As etiquetas de ticket que podem ser usadas. São diferentes das etiquetas de contato e das de negócio. Com o token de login de um usuário, vale a regra da tela: etiquetas restritas a setores, canais ou usuários só aparecem para quem tem acesso a eles. A chave de API vê todas as etiquetas de ticket da empresa.
Exemplos de código — listar etiquetas de ticket
curl "https://api.atys.pro/api/v1/tickets/tags" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/tags', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/tags',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/tags');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/tags', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/tags", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 12,
"name": "Urgente",
"description": null,
"color": "#ef4444"
}
]
}
Atendentes (catálogo)
Os usuários ativos da empresa que podem ser responsáveis ou atendentes de um ticket. O usuário API não aparece aqui.
Exemplos de código — listar atendentes
curl "https://api.atys.pro/api/v1/tickets/users" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/users', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/users',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/users');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/users', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/users", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
},
{
"id": 93,
"name": "Carlos Lima",
"email": "carlos@loja.com.br"
}
]
}
Criar ticket
Abre o ticket como o botão Novo ticket da tela. A message vira a
primeira interação, visível ao contato. O responsável é o usuário autenticado, e o status nasce
Atribuído quando há atendentes ou Não atribuído quando não há. Em seguida a Atys
envia os e-mails de novo ticket aos atendentes, ao criador e aos contatos. Para anexar arquivos,
responda o ticket depois de criado (anexos).
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
subject | string | Sim | Assunto, até 500 caracteres. |
message | string | Sim | Primeira interação, visível ao contato. Aceita HTML simples, como a tela. |
contact_ids | integer[] | Sim | De 1 a 50 contatos da empresa (422 invalid_contact). |
user_ids | integer[] | Não | Atendentes do ticket, do catálogo (422 invalid_user). |
priority_id | integer | Conforme a configuração | Prioridade. É obrigatória por padrão (422 priority_required). |
category_id | integer | Conforme a configuração | Categoria da empresa (422 invalid_category, 422 category_required). |
tag_ids | integer[] | Conforme a configuração | Etiquetas de ticket utilizáveis (422 invalid_tag, 422 tags_required). |
Quais campos são obrigatórios depende dos campos do formulário da empresa.
Exemplos de código — criar ticket
curl -X POST "https://api.atys.pro/api/v1/tickets" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"subject": "Pedido 8841 não chegou",
"message": "Olá, Maria! Abrimos este chamado para acompanhar a entrega do pedido 8841.",
"contact_ids": [5120],
"user_ids": [92],
"priority_id": 1,
"category_id": 7,
"tag_ids": [12]
}'
const response = await fetch('https://api.atys.pro/api/v1/tickets', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"subject": "Pedido 8841 não chegou",
"message": "Olá, Maria! Abrimos este chamado para acompanhar a entrega do pedido 8841.",
"contact_ids": [5120],
"user_ids": [92],
"priority_id": 1,
"category_id": 7,
"tag_ids": [12]
})
});
const { data, error } = await response.json();
import os
import requests
response = requests.post(
'https://api.atys.pro/api/v1/tickets',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
json={
'subject': 'Pedido 8841 não chegou',
'message': 'Olá, Maria! Abrimos este chamado para acompanhar a entrega do pedido 8841.',
'contact_ids': [5120],
'user_ids': [92],
'priority_id': 1,
'category_id': 7,
'tag_ids': [12]
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'subject' => 'Pedido 8841 não chegou',
'message' => 'Olá, Maria! Abrimos este chamado para acompanhar a entrega do pedido 8841.',
'contact_ids' => [5120],
'user_ids' => [92],
'priority_id' => 1,
'category_id' => 7,
'tag_ids' => [12]
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('POST', 'v1/tickets', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'json' => [
'subject' => 'Pedido 8841 não chegou',
'message' => 'Olá, Maria! Abrimos este chamado para acompanhar a entrega do pedido 8841.',
'contact_ids' => [5120],
'user_ids' => [92],
'priority_id' => 1,
'category_id' => 7,
'tag_ids' => [12]
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{
"subject": "Pedido 8841 não chegou",
"message": "Olá, Maria! Abrimos este chamado para acompanhar a entrega do pedido 8841.",
"contact_ids": [5120],
"user_ids": [92],
"priority_id": 1,
"category_id": 7,
"tag_ids": [12]
}`)
req, _ := http.NewRequest("POST", "https://api.atys.pro/api/v1/tickets", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"id": 4521,
"subject": "Pedido 8841 não chegou",
"status": {
"id": 17,
"name": "TICKETS_OPENED_ASSIGNED",
"label": "Atribuído",
"group": "open"
},
"status_id": 17,
"priority": {
"id": 1,
"name": "Alta",
"description": "Prioridade alta"
},
"category": {
"id": 7,
"name": "Financeiro",
"sector": {
"id": 6,
"name": "Suporte"
}
},
"responsible_user": {
"id": 81,
"name": "Integração ERP",
"email": "erp@loja.com.br"
},
"users": [
{
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
}
],
"contacts": [
{
"id": 5120,
"name": "Maria Cliente",
"email": "maria@cliente.com.br"
}
],
"tags": [
{
"id": 12,
"name": "Urgente",
"color": "#ef4444"
}
],
"is_pinned": false,
"unread_count": 0,
"interactions_count": 1,
"last_interaction_at": "2026-11-04T14:05:00-03:00",
"created_at": "2026-11-04T14:05:00-03:00",
"updated_at": "2026-11-04T14:05:00-03:00"
}
}
Listar tickets
Os tickets da empresa, do mais novo para o mais antigo. Por padrão vêm os abertos e pausados, como a lista da tela. Os filtros só estreitam essa lista.
| Parâmetro | Tipo | Descrição |
|---|---|---|
status | string | Grupo: active (padrão: abertos e pausados), open, paused, finished ou all. |
status_id[] | integer[] | Status exatos do catálogo. Quando informado, o filtro status é ignorado. |
priority_id | integer | Prioridade. |
category_id / sector_id | integer | Categoria, ou o setor da categoria. |
responsible_user_id | integer | Atendente responsável. |
user_id | integer | Tickets em que este usuário é atendente. |
contact_id | integer | Tickets de um contato. |
tag_ids[] | integer[] | Tickets com pelo menos uma destas etiquetas. Etiqueta que o usuário não pode usar responde 422 invalid_tag. |
pinned | boolean | 1 traz só os fixados pelo usuário autenticado; 0, só os não fixados. Sem o parâmetro, vêm os dois. |
unread | boolean | 1 traz só os tickets com interações não lidas pelo usuário autenticado; 0, só os sem. |
q | string | Busca da tela: assunto, texto das interações e nome ou e-mail dos contatos. Um número, como 4521 ou #4521, também encontra o ticket por id. |
created_since / created_until | data ISO 8601 | Período de criação. |
updated_since | data ISO 8601 | Tickets alterados a partir desta data, para sincronização incremental. Contam mudanças de status, prioridade, responsável, atendentes, contatos e etiquetas. |
page / per_page | integer | Paginação; per_page de 1 a 100 (padrão 25). |
Exemplos de código — listar tickets
curl "https://api.atys.pro/api/v1/tickets?status=active&contact_id=5120&per_page=25" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets?status=active&contact_id=5120&per_page=25', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets?status=active&contact_id=5120&per_page=25',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets?status=active&contact_id=5120&per_page=25');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'query' => [
'status' => 'active',
'contact_id' => 5120,
'per_page' => 25
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets?status=active&contact_id=5120&per_page=25", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 4521,
"subject": "Pedido 8841 não chegou",
"status": {
"id": 17,
"name": "TICKETS_OPENED_ASSIGNED",
"label": "Atribuído",
"group": "open"
},
"status_id": 17,
"priority": {
"id": 1,
"name": "Alta",
"description": "Prioridade alta"
},
"category": {
"id": 7,
"name": "Financeiro",
"sector": {
"id": 6,
"name": "Suporte"
}
},
"responsible_user": {
"id": 81,
"name": "Integração ERP",
"email": "erp@loja.com.br"
},
"users": [
{
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
}
],
"contacts": [
{
"id": 5120,
"name": "Maria Cliente",
"email": "maria@cliente.com.br"
}
],
"tags": [
{
"id": 12,
"name": "Urgente",
"color": "#ef4444"
}
],
"is_pinned": false,
"unread_count": 0,
"interactions_count": 1,
"last_interaction_at": "2026-11-04T14:05:00-03:00",
"created_at": "2026-11-04T14:05:00-03:00",
"updated_at": "2026-11-04T14:05:00-03:00"
}
],
"meta": {
"page": 1,
"per_page": 25,
"total": 1,
"last_page": 1
}
}
Ver um ticket
O ticket com status, vínculos e os estados do usuário autenticado. Tickets finalizados também continuam acessíveis pelo id.
Exemplos de código — detalhe do ticket
curl "https://api.atys.pro/api/v1/tickets/4521" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/4521',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/4521', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/4521", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"id": 4521,
"subject": "Pedido 8841 não chegou",
"status": {
"id": 17,
"name": "TICKETS_OPENED_ASSIGNED",
"label": "Atribuído",
"group": "open"
},
"status_id": 17,
"priority": {
"id": 1,
"name": "Alta",
"description": "Prioridade alta"
},
"category": {
"id": 7,
"name": "Financeiro",
"sector": {
"id": 6,
"name": "Suporte"
}
},
"responsible_user": {
"id": 81,
"name": "Integração ERP",
"email": "erp@loja.com.br"
},
"users": [
{
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
}
],
"contacts": [
{
"id": 5120,
"name": "Maria Cliente",
"email": "maria@cliente.com.br"
}
],
"tags": [
{
"id": 12,
"name": "Urgente",
"color": "#ef4444"
}
],
"is_pinned": false,
"unread_count": 0,
"interactions_count": 1,
"last_interaction_at": "2026-11-04T14:05:00-03:00",
"created_at": "2026-11-04T14:05:00-03:00",
"updated_at": "2026-11-04T14:05:00-03:00"
}
}
Editar assunto e categoria
Altera o assunto e a categoria. Só muda o que for enviado. Para tirar a categoria, envie
category_id: null; se a configuração da empresa exigir categoria, a resposta é
422 category_required. Status, prioridade, responsável e vínculos têm endpoints próprios
logo abaixo.
| Campo | Tipo | Descrição |
|---|---|---|
subject | string | Novo assunto, sem ficar vazio (422 subject_required). |
category_id | integer | null | Categoria da empresa (422 invalid_category). |
Exemplos de código — editar ticket
curl -X PATCH "https://api.atys.pro/api/v1/tickets/4521" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"subject": "Pedido 8841 não chegou (rota Sul)"
}'
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521', {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"subject": "Pedido 8841 não chegou (rota Sul)"
})
});
const { data, error } = await response.json();
import os
import requests
response = requests.patch(
'https://api.atys.pro/api/v1/tickets/4521',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
json={
'subject': 'Pedido 8841 não chegou (rota Sul)'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'subject' => 'Pedido 8841 não chegou (rota Sul)'
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('PATCH', 'v1/tickets/4521', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'json' => [
'subject' => 'Pedido 8841 não chegou (rota Sul)'
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{
"subject": "Pedido 8841 não chegou (rota Sul)"
}`)
req, _ := http.NewRequest("PATCH", "https://api.atys.pro/api/v1/tickets/4521", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"id": 4521,
"subject": "Pedido 8841 não chegou (rota Sul)",
"status": {
"id": 17,
"name": "TICKETS_OPENED_ASSIGNED",
"label": "Atribuído",
"group": "open"
},
"status_id": 17,
"priority": {
"id": 1,
"name": "Alta",
"description": "Prioridade alta"
},
"category": {
"id": 7,
"name": "Financeiro",
"sector": {
"id": 6,
"name": "Suporte"
}
},
"responsible_user": {
"id": 81,
"name": "Integração ERP",
"email": "erp@loja.com.br"
},
"users": [
{
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
}
],
"contacts": [
{
"id": 5120,
"name": "Maria Cliente",
"email": "maria@cliente.com.br"
}
],
"tags": [
{
"id": 12,
"name": "Urgente",
"color": "#ef4444"
}
],
"is_pinned": false,
"unread_count": 0,
"interactions_count": 1,
"last_interaction_at": "2026-11-04T14:05:00-03:00",
"created_at": "2026-11-04T14:05:00-03:00",
"updated_at": "2026-11-04T15:10:00-03:00"
}
}
Alterar status
Muda o status, como o menu "Atualizar status" da tela, e dispara as integrações ligadas ao ticket.
Só valem os status com settable: true no catálogo;
qualquer outro responde 422 invalid_status, e details.allowed_status_ids
lista os aceitos. Enviar o status que o ticket já tem devolve o ticket sem alterar nada. Para
reabrir um ticket finalizado, use 19 (Reaberto).
Exemplos de código — alterar status do ticket
curl -X POST "https://api.atys.pro/api/v1/tickets/4521/status" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"status_id": 25
}'
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/status', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"status_id": 25
})
});
const { data, error } = await response.json();
import os
import requests
response = requests.post(
'https://api.atys.pro/api/v1/tickets/4521/status',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
json={
'status_id': 25
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/status');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'status_id' => 25
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('POST', 'v1/tickets/4521/status', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'json' => [
'status_id' => 25
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{
"status_id": 25
}`)
req, _ := http.NewRequest("POST", "https://api.atys.pro/api/v1/tickets/4521/status", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"id": 4521,
"subject": "Pedido 8841 não chegou",
"status": {
"id": 25,
"name": "TICKETS_FINISHED_RESOLVED",
"label": "Resolvido",
"group": "finished"
},
"status_id": 25,
"priority": {
"id": 1,
"name": "Alta",
"description": "Prioridade alta"
},
"category": {
"id": 7,
"name": "Financeiro",
"sector": {
"id": 6,
"name": "Suporte"
}
},
"responsible_user": {
"id": 81,
"name": "Integração ERP",
"email": "erp@loja.com.br"
},
"users": [
{
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
}
],
"contacts": [
{
"id": 5120,
"name": "Maria Cliente",
"email": "maria@cliente.com.br"
}
],
"tags": [
{
"id": 12,
"name": "Urgente",
"color": "#ef4444"
}
],
"is_pinned": false,
"unread_count": 0,
"interactions_count": 1,
"last_interaction_at": "2026-11-04T14:05:00-03:00",
"created_at": "2026-11-04T14:05:00-03:00",
"updated_at": "2026-11-04T16:40:00-03:00"
}
}
Alterar prioridade
Define a prioridade (422 invalid_priority se ela não existir). A regra é a da tela: um
usuário que não é administrador só altera a prioridade de tickets em que é atendente. O usuário API
da chave é administrador da empresa.
Exemplos de código — alterar prioridade do ticket
curl -X POST "https://api.atys.pro/api/v1/tickets/4521/priority" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"priority_id": 3
}'
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/priority', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"priority_id": 3
})
});
const { data, error } = await response.json();
import os
import requests
response = requests.post(
'https://api.atys.pro/api/v1/tickets/4521/priority',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
json={
'priority_id': 3
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/priority');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'priority_id' => 3
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('POST', 'v1/tickets/4521/priority', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'json' => [
'priority_id' => 3
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{
"priority_id": 3
}`)
req, _ := http.NewRequest("POST", "https://api.atys.pro/api/v1/tickets/4521/priority", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"id": 4521,
"subject": "Pedido 8841 não chegou",
"status": {
"id": 17,
"name": "TICKETS_OPENED_ASSIGNED",
"label": "Atribuído",
"group": "open"
},
"status_id": 17,
"priority": {
"id": 3,
"name": "Baixa",
"description": "Prioridade baixa"
},
"category": {
"id": 7,
"name": "Financeiro",
"sector": {
"id": 6,
"name": "Suporte"
}
},
"responsible_user": {
"id": 81,
"name": "Integração ERP",
"email": "erp@loja.com.br"
},
"users": [
{
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
}
],
"contacts": [
{
"id": 5120,
"name": "Maria Cliente",
"email": "maria@cliente.com.br"
}
],
"tags": [
{
"id": 12,
"name": "Urgente",
"color": "#ef4444"
}
],
"is_pinned": false,
"unread_count": 0,
"interactions_count": 1,
"last_interaction_at": "2026-11-04T14:05:00-03:00",
"created_at": "2026-11-04T14:05:00-03:00",
"updated_at": "2026-11-04T15:12:00-03:00"
}
}
Atribuir responsável
Define o atendente responsável e coloca o ticket em Atribuído, como os itens "Atribuir para
mim" e "Atribuir para outro" da tela. Atribuir a outra pessoa pede a permissão atribuir
tickets. O responsável precisa ser um usuário ativo da empresa, do
catálogo (422 invalid_user). Atribuir não
inclui o usuário entre os atendentes do ticket; para isso, use atendentes
do ticket.
Exemplos de código — atribuir responsável
curl -X POST "https://api.atys.pro/api/v1/tickets/4521/assign" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"user_id": 92
}'
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/assign', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"user_id": 92
})
});
const { data, error } = await response.json();
import os
import requests
response = requests.post(
'https://api.atys.pro/api/v1/tickets/4521/assign',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
json={
'user_id': 92
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/assign');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'user_id' => 92
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('POST', 'v1/tickets/4521/assign', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'json' => [
'user_id' => 92
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{
"user_id": 92
}`)
req, _ := http.NewRequest("POST", "https://api.atys.pro/api/v1/tickets/4521/assign", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"id": 4521,
"subject": "Pedido 8841 não chegou",
"status": {
"id": 17,
"name": "TICKETS_OPENED_ASSIGNED",
"label": "Atribuído",
"group": "open"
},
"status_id": 17,
"priority": {
"id": 1,
"name": "Alta",
"description": "Prioridade alta"
},
"category": {
"id": 7,
"name": "Financeiro",
"sector": {
"id": 6,
"name": "Suporte"
}
},
"responsible_user": {
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
},
"users": [
{
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
}
],
"contacts": [
{
"id": 5120,
"name": "Maria Cliente",
"email": "maria@cliente.com.br"
}
],
"tags": [
{
"id": 12,
"name": "Urgente",
"color": "#ef4444"
}
],
"is_pinned": false,
"unread_count": 0,
"interactions_count": 1,
"last_interaction_at": "2026-11-04T14:05:00-03:00",
"created_at": "2026-11-04T14:05:00-03:00",
"updated_at": "2026-11-04T15:15:00-03:00"
}
}
Atendentes do ticket
Os atendentes que participam do ticket, os mesmos de "Adicionar participante" na tela. O
PUT define a lista inteira: quem não estiver nela sai, e quem faltar entra. Quem continua
mantém o próprio contador de não lidas. Envie user_ids: [] para tirar todos. Usuário que
não é ativo na empresa responde 422 invalid_user.
Exemplos de código — listar atendentes do ticket
curl "https://api.atys.pro/api/v1/tickets/4521/users" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/users', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/4521/users',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/users');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/4521/users', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/4521/users", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
}
]
}
Exemplos de código — definir atendentes do ticket
curl -X PUT "https://api.atys.pro/api/v1/tickets/4521/users" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"user_ids": [92, 93]
}'
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/users', {
method: 'PUT',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"user_ids": [92, 93]
})
});
const { data, error } = await response.json();
import os
import requests
response = requests.put(
'https://api.atys.pro/api/v1/tickets/4521/users',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
json={
'user_ids': [92, 93]
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/users');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'user_ids' => [92, 93]
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('PUT', 'v1/tickets/4521/users', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'json' => [
'user_ids' => [92, 93]
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{
"user_ids": [92, 93]
}`)
req, _ := http.NewRequest("PUT", "https://api.atys.pro/api/v1/tickets/4521/users", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
},
{
"id": 93,
"name": "Carlos Lima",
"email": "carlos@loja.com.br"
}
]
}
Contatos do ticket
Os contatos do ticket. O PUT define a lista inteira, como "Adicionar contato" e
"Remover contato" na tela. Quem continua mantém o mesmo link de acompanhamento
(acesso do contato), e quem entra ganha um link novo. Envie
contact_ids: [] para tirar todos. Contato que não é da empresa responde
422 invalid_contact. Nome e e-mail seguem as permissões do usuário API.
Exemplos de código — listar contatos do ticket
curl "https://api.atys.pro/api/v1/tickets/4521/contacts" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/contacts', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/4521/contacts',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/contacts');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/4521/contacts', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/4521/contacts", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 5120,
"name": "Maria Cliente",
"email": "maria@cliente.com.br"
}
]
}
Exemplos de código — definir contatos do ticket
curl -X PUT "https://api.atys.pro/api/v1/tickets/4521/contacts" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"contact_ids": [5120, 5133]
}'
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/contacts', {
method: 'PUT',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"contact_ids": [5120, 5133]
})
});
const { data, error } = await response.json();
import os
import requests
response = requests.put(
'https://api.atys.pro/api/v1/tickets/4521/contacts',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
json={
'contact_ids': [5120, 5133]
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/contacts');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'contact_ids' => [5120, 5133]
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('PUT', 'v1/tickets/4521/contacts', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'json' => [
'contact_ids' => [5120, 5133]
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{
"contact_ids": [5120, 5133]
}`)
req, _ := http.NewRequest("PUT", "https://api.atys.pro/api/v1/tickets/4521/contacts", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 5120,
"name": "Maria Cliente",
"email": "maria@cliente.com.br"
},
{
"id": 5133,
"name": "João Comprador",
"email": "joao@cliente.com.br"
}
]
}
Etiquetas do ticket
As etiquetas de ticket. O PUT define a lista inteira com as
etiquetas que o usuário pode usar
(422 invalid_tag). Etiquetas restritas que o usuário não enxerga e já estavam no ticket
continuam lá. Envie tag_ids: [] para tirar todas; se a configuração exigir etiquetas, a
resposta é 422 tags_required.
Exemplos de código — listar etiquetas do ticket
curl "https://api.atys.pro/api/v1/tickets/4521/tags" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/tags', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/4521/tags',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/tags');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/4521/tags', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/4521/tags", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 12,
"name": "Urgente",
"color": "#ef4444"
}
]
}
Exemplos de código — definir etiquetas do ticket
curl -X PUT "https://api.atys.pro/api/v1/tickets/4521/tags" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"tag_ids": [12]
}'
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/tags', {
method: 'PUT',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"tag_ids": [12]
})
});
const { data, error } = await response.json();
import os
import requests
response = requests.put(
'https://api.atys.pro/api/v1/tickets/4521/tags',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
json={
'tag_ids': [12]
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/tags');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'tag_ids' => [12]
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('PUT', 'v1/tickets/4521/tags', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'json' => [
'tag_ids' => [12]
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{
"tag_ids": [12]
}`)
req, _ := http.NewRequest("PUT", "https://api.atys.pro/api/v1/tickets/4521/tags", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 12,
"name": "Urgente",
"color": "#ef4444"
}
]
}
Fixar e desafixar
Fixa o ticket no topo da lista do usuário autenticado. Como na tela, cada usuário pode ter até
3 tickets fixados; acima disso, a resposta é 422 pin_limit_reached.
Fixar um ticket que já está fixado, ou desafixar um que não está, devolve o ticket sem alterar
nada. Para zerar as interações não lidas, veja marcar como
lidas.
Exemplos de código — fixar ticket
curl -X POST "https://api.atys.pro/api/v1/tickets/4521/pin" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/pin', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.post(
'https://api.atys.pro/api/v1/tickets/4521/pin',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/pin');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('POST', 'v1/tickets/4521/pin', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("POST", "https://api.atys.pro/api/v1/tickets/4521/pin", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"id": 4521,
"subject": "Pedido 8841 não chegou",
"status": {
"id": 17,
"name": "TICKETS_OPENED_ASSIGNED",
"label": "Atribuído",
"group": "open"
},
"status_id": 17,
"priority": {
"id": 1,
"name": "Alta",
"description": "Prioridade alta"
},
"category": {
"id": 7,
"name": "Financeiro",
"sector": {
"id": 6,
"name": "Suporte"
}
},
"responsible_user": {
"id": 81,
"name": "Integração ERP",
"email": "erp@loja.com.br"
},
"users": [
{
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
}
],
"contacts": [
{
"id": 5120,
"name": "Maria Cliente",
"email": "maria@cliente.com.br"
}
],
"tags": [
{
"id": 12,
"name": "Urgente",
"color": "#ef4444"
}
],
"is_pinned": true,
"unread_count": 0,
"interactions_count": 1,
"last_interaction_at": "2026-11-04T14:05:00-03:00",
"created_at": "2026-11-04T14:05:00-03:00",
"updated_at": "2026-11-04T14:05:00-03:00"
}
}
Exemplos de código — desafixar ticket
curl -X DELETE "https://api.atys.pro/api/v1/tickets/4521/pin" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/pin', {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
console.log(response.status); // 204 = excluído
import os
import requests
response = requests.delete(
'https://api.atys.pro/api/v1/tickets/4521/pin',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
print(response.status_code) # 204 = excluído
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/pin');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('DELETE', 'v1/tickets/4521/pin', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("DELETE", "https://api.atys.pro/api/v1/tickets/4521/pin", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"id": 4521,
"subject": "Pedido 8841 não chegou",
"status": {
"id": 17,
"name": "TICKETS_OPENED_ASSIGNED",
"label": "Atribuído",
"group": "open"
},
"status_id": 17,
"priority": {
"id": 1,
"name": "Alta",
"description": "Prioridade alta"
},
"category": {
"id": 7,
"name": "Financeiro",
"sector": {
"id": 6,
"name": "Suporte"
}
},
"responsible_user": {
"id": 81,
"name": "Integração ERP",
"email": "erp@loja.com.br"
},
"users": [
{
"id": 92,
"name": "Ana Atendente",
"email": "ana@loja.com.br"
}
],
"contacts": [
{
"id": 5120,
"name": "Maria Cliente",
"email": "maria@cliente.com.br"
}
],
"tags": [
{
"id": 12,
"name": "Urgente",
"color": "#ef4444"
}
],
"is_pinned": false,
"unread_count": 0,
"interactions_count": 1,
"last_interaction_at": "2026-11-04T14:05:00-03:00",
"created_at": "2026-11-04T14:05:00-03:00",
"updated_at": "2026-11-04T14:05:00-03:00"
}
}
Campos do formulário
É a configuração de Configurações → Campos do ticket: quais campos aparecem no formulário de novo
ticket e quais são obrigatórios. Ela vale para a tela e para criar ticket
pela API. Sem configuração gravada, prioridade é obrigatória e categoria e etiquetas são opcionais.
O setor não é gravado no ticket (ele só filtra as categorias), então sector_required não
bloqueia a criação.
O PUT altera só os campos enviados e exige um administrador da empresa;
o usuário API da chave é administrador. Outros usuários recebem 403 forbidden.
| Campo | Tipo | Descrição |
|---|---|---|
priority_visible / priority_required | boolean | Prioridade aparece / é obrigatória. |
sector_visible / sector_required | boolean | Setor aparece / é obrigatório no formulário da tela. |
category_visible / category_required | boolean | Categoria aparece / é obrigatória. |
tags_visible / tags_required | boolean | Etiquetas aparecem / são obrigatórias. |
Um campo só é obrigatório quando está visível e obrigatório ao mesmo tempo.
Exemplos de código — ver campos do formulário
curl "https://api.atys.pro/api/v1/tickets/visibility-fields" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/visibility-fields', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/visibility-fields',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/visibility-fields');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/visibility-fields', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/visibility-fields", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"priority_visible": true,
"priority_required": true,
"sector_visible": true,
"sector_required": false,
"category_visible": true,
"category_required": false,
"tags_visible": true,
"tags_required": false
}
}
Exemplos de código — alterar campos do formulário
curl -X PUT "https://api.atys.pro/api/v1/tickets/visibility-fields" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"category_required": true
}'
const response = await fetch('https://api.atys.pro/api/v1/tickets/visibility-fields', {
method: 'PUT',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"category_required": true
})
});
const { data, error } = await response.json();
import os
import requests
response = requests.put(
'https://api.atys.pro/api/v1/tickets/visibility-fields',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
json={
'category_required': True
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/visibility-fields');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'category_required' => true
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('PUT', 'v1/tickets/visibility-fields', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'json' => [
'category_required' => true
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{
"category_required": true
}`)
req, _ := http.NewRequest("PUT", "https://api.atys.pro/api/v1/tickets/visibility-fields", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"priority_visible": true,
"priority_required": true,
"sector_visible": true,
"sector_required": false,
"category_visible": true,
"category_required": true,
"tags_visible": true,
"tags_required": false
}
}
Excluir ticket
A plataforma não exclui tickets, e a API também não. Para encerrar um ticket, use
alterar status com um status do grupo finished. O histórico
continua acessível pelo id.
Interações do ticket
Cada mensagem trocada no ticket é uma interação: as respostas da equipe e do contato e as notas internas. É o mesmo histórico da tela do ticket na Atys. Toda interação da v1 tem o mesmo formato:
| Campo | Descrição |
|---|---|
visibility | public (resposta que o contato vê no portal do ticket e recebe por e-mail) ou internal (nota interna, só a equipe vê). |
text | O conteúdo, como foi gravado. A tela aceita HTML simples (negrito, listas, links), então respostas escritas na plataforma podem trazer tags. |
author | Quem escreveu: type = user (alguém da equipe ou o usuário da chave) ou contact (o contato, pelo portal do ticket), com id e name. |
files | Anexos da interação: name, type (image, audio, video ou document) e url. |
Datas em ISO 8601.
Histórico de interações
As interações de um ticket, da mais recente para a mais antiga. Use order=asc para ler
na ordem da conversa. O ticket precisa ser da empresa da chave; de outra forma a resposta é
404.
| Parâmetro | Tipo | Descrição |
|---|---|---|
visibility | string | Só public ou só internal. |
order | string | desc (padrão, mais recentes primeiro) ou asc. |
page / per_page | integer | Paginação; per_page de 1 a 100 (padrão 25). |
Exemplos de código — listar interações
curl "https://api.atys.pro/api/v1/tickets/4521/interactions?order=asc" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/interactions?order=asc', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/4521/interactions?order=asc',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/interactions?order=asc');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/4521/interactions', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'query' => [
'order' => 'asc'
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/4521/interactions?order=asc", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 99120,
"ticket_id": 4521,
"visibility": "public",
"text": "Meu pedido 8841 ainda não chegou.",
"author": {
"type": "contact",
"id": 5120,
"name": "Maria Cliente"
},
"files": [],
"created_at": "2026-11-04T14:05:00-03:00",
"updated_at": "2026-11-04T14:05:00-03:00"
},
{
"id": 99121,
"ticket_id": 4521,
"visibility": "public",
"text": "Olá, Maria! O pedido saiu hoje e chega amanhã.",
"author": {
"type": "user",
"id": 81,
"name": "Integração ERP"
},
"files": [],
"created_at": "2026-11-04T15:20:00-03:00",
"updated_at": "2026-11-04T15:20:00-03:00"
},
{
"id": 99122,
"ticket_id": 4521,
"visibility": "internal",
"text": "Transportadora confirmou atraso na rota. Acompanhar até amanhã.",
"author": {
"type": "user",
"id": 81,
"name": "Integração ERP"
},
"files": [],
"created_at": "2026-11-04T15:22:00-03:00",
"updated_at": "2026-11-04T15:22:00-03:00"
}
],
"meta": {
"page": 1,
"per_page": 25,
"total": 3,
"last_page": 1
}
}
Uma interação específica do ticket. Se ela for de outro ticket, a resposta é 404.
Exemplos de código — ver interação
curl "https://api.atys.pro/api/v1/tickets/4521/interactions/99121" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/interactions/99121', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/4521/interactions/99121',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/interactions/99121');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/4521/interactions/99121', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/4521/interactions/99121", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"id": 99121,
"ticket_id": 4521,
"visibility": "public",
"text": "Olá, Maria! O pedido saiu hoje e chega amanhã.",
"author": {
"type": "user",
"id": 81,
"name": "Integração ERP"
},
"files": [],
"created_at": "2026-11-04T15:20:00-03:00",
"updated_at": "2026-11-04T15:20:00-03:00"
}
}
Responder ao contato
Registra uma resposta no ticket, como o botão Enviar da tela. A resposta fica no nome do usuário da chave e passa a ser a última interação do ticket. Os atendentes e os contatos do ticket recebem o e-mail de atualização, com o link para acompanhar o ticket. Os outros atendentes veem o ticket como não lido. Quem estiver com a tela aberta recebe a resposta na hora.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
visibility | string | Sim | public para responder ao contato. |
text | string | Sim | Texto da resposta. Aceita HTML simples. Pode ficar vazio se a interação levar anexos. |
notify | boolean | Não | Padrão true. Com false, a resposta entra no histórico sem enviar e-mail. Serve, por exemplo, para importar conversas antigas. |
Exemplos de código — responder ao contato
curl -X POST "https://api.atys.pro/api/v1/tickets/4521/interactions" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"visibility": "public",
"text": "Olá, Maria! O pedido saiu hoje e chega amanhã."
}'
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/interactions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"visibility": "public",
"text": "Olá, Maria! O pedido saiu hoje e chega amanhã."
})
});
const { data, error } = await response.json();
import os
import requests
response = requests.post(
'https://api.atys.pro/api/v1/tickets/4521/interactions',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
json={
'visibility': 'public',
'text': 'Olá, Maria! O pedido saiu hoje e chega amanhã.'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/interactions');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'visibility' => 'public',
'text' => 'Olá, Maria! O pedido saiu hoje e chega amanhã.'
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('POST', 'v1/tickets/4521/interactions', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'json' => [
'visibility' => 'public',
'text' => 'Olá, Maria! O pedido saiu hoje e chega amanhã.'
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{
"visibility": "public",
"text": "Olá, Maria! O pedido saiu hoje e chega amanhã."
}`)
req, _ := http.NewRequest("POST", "https://api.atys.pro/api/v1/tickets/4521/interactions", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"id": 99121,
"ticket_id": 4521,
"visibility": "public",
"text": "Olá, Maria! O pedido saiu hoje e chega amanhã.",
"author": {
"type": "user",
"id": 81,
"name": "Integração ERP"
},
"files": [],
"created_at": "2026-11-04T15:20:00-03:00",
"updated_at": "2026-11-04T15:20:00-03:00"
}
}
Nota interna
Com visibility: "internal", a interação é uma nota para a equipe, como o
comentário interno da tela. O contato não vê a nota no portal e ninguém recebe
e-mail. Os atendentes do ticket veem o ticket como não lido.
Exemplos de código — registrar nota interna
curl -X POST "https://api.atys.pro/api/v1/tickets/4521/interactions" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"visibility": "internal",
"text": "Transportadora confirmou atraso na rota. Acompanhar até amanhã."
}'
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/interactions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"visibility": "internal",
"text": "Transportadora confirmou atraso na rota. Acompanhar até amanhã."
})
});
const { data, error } = await response.json();
import os
import requests
response = requests.post(
'https://api.atys.pro/api/v1/tickets/4521/interactions',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
json={
'visibility': 'internal',
'text': 'Transportadora confirmou atraso na rota. Acompanhar até amanhã.'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/interactions');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'visibility' => 'internal',
'text' => 'Transportadora confirmou atraso na rota. Acompanhar até amanhã.'
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('POST', 'v1/tickets/4521/interactions', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'json' => [
'visibility' => 'internal',
'text' => 'Transportadora confirmou atraso na rota. Acompanhar até amanhã.'
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{
"visibility": "internal",
"text": "Transportadora confirmou atraso na rota. Acompanhar até amanhã."
}`)
req, _ := http.NewRequest("POST", "https://api.atys.pro/api/v1/tickets/4521/interactions", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"id": 99122,
"ticket_id": 4521,
"visibility": "internal",
"text": "Transportadora confirmou atraso na rota. Acompanhar até amanhã.",
"author": {
"type": "user",
"id": 81,
"name": "Integração ERP"
},
"files": [],
"created_at": "2026-11-04T15:22:00-03:00",
"updated_at": "2026-11-04T15:22:00-03:00"
}
}
Enviar anexos
Anexos vão junto com a interação, no mesmo endpoint, em multipart/form-data. Use um
campo files[] por arquivo, até 10 arquivos de até 100 MB cada. Os campos
visibility, text e notify são os mesmos da
resposta. Com anexos, text pode ficar vazio.
Em multipart, envie notify como true/false ou 1/0.
Os arquivos vão para o armazenamento da empresa: o Google Drive, se a empresa tiver um conectado, ou
o armazenamento da Atys. O type de cada anexo vem da extensão do arquivo, como na
tela. Uma nota interna com anexos mantém os arquivos só para a equipe.
Exemplos de código — responder com anexos
curl -X POST "https://api.atys.pro/api/v1/tickets/4521/interactions" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-F "visibility=public" \
-F "text=Segue o comprovante de envio." \
-F "files[]=@comprovante.pdf" \
-F "files[]=@foto-caixa.jpg"
const form = new FormData();
form.append('visibility', 'public');
form.append('text', 'Segue o comprovante de envio.');
form.append('files[]', comprovante); // File ou Blob
form.append('files[]', fotoCaixa);
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/interactions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
},
body: form // não defina Content-Type: o navegador/Node põe o boundary
});
const { data, error } = await response.json();
import os
import requests
with open('comprovante.pdf', 'rb') as pdf, open('foto-caixa.jpg', 'rb') as foto:
response = requests.post(
'https://api.atys.pro/api/v1/tickets/4521/interactions',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
data={'visibility': 'public', 'text': 'Segue o comprovante de envio.'},
files=[('files[]', pdf), ('files[]', foto)]
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/interactions');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
CURLOPT_POSTFIELDS => [
'visibility' => 'public',
'text' => 'Segue o comprovante de envio.',
'files[0]' => new CURLFile('comprovante.pdf'),
'files[1]' => new CURLFile('foto-caixa.jpg'),
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('POST', 'v1/tickets/4521/interactions', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'multipart' => [
['name' => 'visibility', 'contents' => 'public'],
['name' => 'text', 'contents' => 'Segue o comprovante de envio.'],
['name' => 'files[]', 'contents' => fopen('comprovante.pdf', 'r'), 'filename' => 'comprovante.pdf'],
['name' => 'files[]', 'contents' => fopen('foto-caixa.jpg', 'r'), 'filename' => 'foto-caixa.jpg'],
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"io"
"mime/multipart"
"net/http"
"os"
)
func main() {
var body bytes.Buffer
form := multipart.NewWriter(&body)
form.WriteField("visibility", "public")
form.WriteField("text", "Segue o comprovante de envio.")
for _, name := range []string{"comprovante.pdf", "foto-caixa.jpg"} {
part, _ := form.CreateFormFile("files[]", name)
file, _ := os.Open(name)
io.Copy(part, file)
file.Close()
}
form.Close()
req, _ := http.NewRequest("POST", "https://api.atys.pro/api/v1/tickets/4521/interactions", &body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", form.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"id": 99123,
"ticket_id": 4521,
"visibility": "public",
"text": "Segue o comprovante de envio.",
"author": {
"type": "user",
"id": 81,
"name": "Integração ERP"
},
"files": [
{
"id": 3310,
"name": "comprovante.pdf",
"type": "document",
"url": "https://files.atys.pro/storage/files/company-12/tickets/comprovante.pdf",
"created_at": "2026-11-04T15:25:00-03:00"
}
],
"created_at": "2026-11-04T15:25:00-03:00",
"updated_at": "2026-11-04T15:25:00-03:00"
}
}
Erros específicos (422): too_many_files (mais de 10 arquivos),
invalid_file (upload incompleto ou acima de 100 MB) e interaction_failed
(não foi possível gravar a interação ou guardar os arquivos; confira o armazenamento da empresa).
Anexos do ticket
Todos os arquivos anexados nas interações do ticket, do mais recente para o mais antigo. Cada item
diz de qual interação veio (interaction_id) e se ela é pública ou nota interna.
Exemplos de código — listar anexos do ticket
curl "https://api.atys.pro/api/v1/tickets/4521/files" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/files', {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.get(
'https://api.atys.pro/api/v1/tickets/4521/files',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/files');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('GET', 'v1/tickets/4521/files', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("GET", "https://api.atys.pro/api/v1/tickets/4521/files", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": [
{
"id": 3310,
"name": "comprovante.pdf",
"type": "document",
"url": "https://files.atys.pro/storage/files/company-12/tickets/comprovante.pdf",
"created_at": "2026-11-04T15:25:00-03:00",
"interaction_id": 99123,
"visibility": "public"
}
],
"meta": {
"page": 1,
"per_page": 25,
"total": 1,
"last_page": 1
}
}
Marcar como lidas
Zera o contador de interações não lidas do usuário da chave neste ticket, como abrir o ticket na
tela. Só os atendentes do ticket têm esse contador. Se o usuário da chave não for atendente do ticket,
a resposta é 422 not_ticket_user.
Exemplos de código — marcar interações como lidas
curl -X POST "https://api.atys.pro/api/v1/tickets/4521/interactions/read" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json"
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/interactions/read', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json'
}
});
const { data, error } = await response.json();
import os
import requests
response = requests.post(
'https://api.atys.pro/api/v1/tickets/4521/interactions/read',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/interactions/read');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('POST', 'v1/tickets/4521/interactions/read', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"net/http"
"os"
)
func main() {
req, _ := http.NewRequest("POST", "https://api.atys.pro/api/v1/tickets/4521/interactions/read", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
Acesso do contato
Cada contato do ticket tem um link para acompanhar o ticket no portal da Atys. Pelo portal, ele lê as respostas públicas e responde. É o mesmo link do botão Acompanhar ticket dos e-mails do ticket. O link sozinho não abre o ticket: ao acessá-lo, o contato recebe um código de verificação no e-mail dele e só entra com esse código.
Este endpoint devolve o link de um contato, para você enviar pelo seu canal (WhatsApp, SMS, área do
cliente). Com send_email: true, a Atys também reenvia ao contato o e-mail com o link,
pelo remetente de e-mails de Tickets da empresa. O link não muda a cada chamada, então os e-mails
que o contato já recebeu continuam funcionando.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
contact_id | integer | Sim | Contato vinculado ao ticket (id da API de Contatos). |
send_email | boolean | Não | Padrão false. true reenvia o link por e-mail ao contato. |
Exemplos de código — link de acompanhamento do contato
curl -X POST "https://api.atys.pro/api/v1/tickets/4521/contact-access" \
-H "Authorization: Bearer atys_live_SUA_CHAVE" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"contact_id": 5120,
"send_email": true
}'
const response = await fetch('https://api.atys.pro/api/v1/tickets/4521/contact-access', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ATYS_API_KEY}`,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
"contact_id": 5120,
"send_email": true
})
});
const { data, error } = await response.json();
import os
import requests
response = requests.post(
'https://api.atys.pro/api/v1/tickets/4521/contact-access',
headers={
'Authorization': f"Bearer {os.environ['ATYS_API_KEY']}",
'Accept': 'application/json'
},
json={
'contact_id': 5120,
'send_email': True
}
)
result = response.json()
<?php
$ch = curl_init('https://api.atys.pro/api/v1/tickets/4521/contact-access');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer '.getenv('ATYS_API_KEY'),
'Accept: application/json',
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'contact_id' => 5120,
'send_email' => true
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
<?php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.atys.pro/api/']);
$response = $client->request('POST', 'v1/tickets/4521/contact-access', [
'headers' => [
'Authorization' => 'Bearer '.getenv('ATYS_API_KEY'),
'Accept' => 'application/json',
],
'json' => [
'contact_id' => 5120,
'send_email' => true
],
]);
$result = json_decode($response->getBody(), true);
package main
import (
"bytes"
"net/http"
"os"
)
func main() {
body := []byte(`{
"contact_id": 5120,
"send_email": true
}`)
req, _ := http.NewRequest("POST", "https://api.atys.pro/api/v1/tickets/4521/contact-access", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("ATYS_API_KEY"))
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
}
{
"data": {
"contact": {
"id": 5120,
"name": "Maria Cliente",
"email": "maria@cliente.com.br"
},
"url": "https://app.atys.pro/ticket/view/0b6f8c2e-5d1a-4c7e-9f3b-2a8d4e6c1f90",
"email_sent": true
}
}
Erros específicos (422): contact_not_in_ticket (o contato não está
vinculado ao ticket; vincule-o antes nos contatos do ticket), contact_without_email
(pediu send_email, mas o contato não tem e-mail) e email_failed (o envio
falhou; confira o remetente de e-mails de Tickets nas configurações da empresa). Sem e-mail
cadastrado, o contato também não recebe o código de verificação do portal.
Erros
Todo erro da v1 tem o mesmo formato: {"error": {"code", "message", "details"}}. Use o
code no seu tratamento; a message é para leitura humana.
422 validation_failed — dados inválidos
Campo obrigatório ausente ou com formato errado. details traz os erros por campo.
{
"error": {
"code": "validation_failed",
"message": "The title field is required.",
"details": { "title": ["The title field is required."] }
}
}
422 invalid_contact / invalid_user / invalid_tag / invalid_category / invalid_priority / invalid_status
Algum id não é da empresa ou não pode ser usado. Em invalid_status, details.allowed_status_ids traz os status aceitos.
422 priority_required / category_required / tags_required / subject_required / message_required
A configuração de campos da empresa exige esse dado ao abrir o ticket (veja campos do formulário).
422 pin_limit_reached / not_ticket_user / contact_not_in_ticket / contact_without_email
Limite de 3 tickets fixados, usuário que não participa do ticket, contato que não é do ticket ou sem e-mail para o acesso ao portal.
422 too_many_files / invalid_file / interaction_failed / email_failed
Mais de 10 anexos ou arquivo não permitido, falha ao registrar a interação ou ao enviar o e-mail ao contato.
404 not_found
O ticket, a interação ou o anexo não existe ou não é visível para a chave.
403 forbidden
A chave não tem a permissão de Tickets necessária, ou o usuário API não tem a permissão na plataforma.
401 unauthenticated
Chave ausente, inválida, revogada ou expirada.