Primeiros passos
Dados do catálogo de produtos do TikTok Shop em JSON, cobrados por crédito. Esta é a referência da versão 1.
URL base
https://developers.sendyx.com/v1
O contrato completo em formato OpenAPI está em /openapi.json.
Autenticação
Crie uma chave no console da Sendyx e envie no cabeçalho Authorization: Bearer sdx_live_.... Guarde a chave em uma variável de ambiente e nunca a coloque em código, em repositório ou em navegador. Ela é mostrada uma única vez.
Créditos
Cada requisição de lista ou de detalhe de qualquer entidade consome 0,10 crédito. Portanto 1 crédito equivale a 10 requisições. São gratuitos a árvore de categorias (GET /v1/categories) e o saldo (GET /v1/account/usage); as demais rotas de categorias, como GET /v1/categories/ranking, consomem o mesmo que as outras. O custo de cada rota aparece no topo da página dela.
Os contatos de criador estão indisponíveis por enquanto. A rota aparece no contrato, mas responde 503 sem cobrar enquanto o recurso não é liberado.
Se o serviço de dados estiver indisponível, a resposta é 503 e nenhum crédito é cobrado.
É preciso comprar créditos para usar a API. Uma conta nova começa com saldo zero, sem crédito de cortesia, e as rotas pagas respondem 402 até a primeira compra, feita no console da Sendyx. Créditos comprados não vencem.
O custo é debitado antes de a resposta ser servida. Requisição com parâmetro inválido (400) não cobra nada, e se ela terminar em erro depois da cobrança o crédito é devolvido na hora. Sem saldo suficiente a resposta é 402.
Cabeçalhos da resposta
| Cabeçalho | Significado |
|---|---|
| x-credits-cost | Créditos cobrados por esta resposta, sempre com duas casas decimais (por exemplo 0.10). Vem nas respostas 200, no 402 (com 0.00) e nos erros que acontecem depois da cobrança e foram estornados, como 404 e 503 (com 0.00). Não vêm no 401, no 429 nem nos 400 de parâmetro, que são recusados antes da cobrança. |
| x-credits-remaining | Saldo restante em créditos, sempre com duas casas decimais (por exemplo 4.90). Nas mesmas respostas do cabeçalho acima; no 402 é o saldo atual. |
| x-request-id | Identificador da requisição. Informe-o ao falar com o suporte. |
| Retry-After | Presente no 429 e no 503: segundos até poder tentar de novo. |
As rotas /v1 aceitam só GET. Um HEAD recebe 405 com Allow: GET, sem consulta e sem cobrança.
Nos cabeçalhos os créditos são texto com duas casas. No corpo JSON os números são numéricos e o JSON não preserva zeros à direita: 0.10 no cabeçalho vira 0.1 no corpo.
Idade dos dados
As rotas de vídeos, criadores, categorias (ranking e detalhe), lojas, lives e análise de produto trazem meta.fetchedAt, o instante (ISO 8601) em que o dado foi obtido. As rotas de produtos e a árvore de categorias trazem meta.dataUpTo, o dia mais recente dos dados, no formato yyyy-MM-dd; a fonte tem um dia de atraso. Se o serviço de dados estiver indisponível, a resposta é 503 e nada é cobrado.
Formato de erro
Todo erro tem o formato { "error", "message", "requestId" }. O campo error é estável e pode ser usado em código.
| Código | error | Quando |
|---|---|---|
| 401 | missing_credentials | Cabeçalho Authorization ausente. |
| 401 | invalid_credentials | Chave inválida ou revogada. |
| 402 | insufficient_credits | Saldo menor que o custo. Traz required e available, em créditos. |
| 429 | rate_limited | Limite de requisições excedido. Veja o cabeçalho Retry-After. |
| 400 | validation_error | Parâmetro inválido, desconhecido ou fora dos limites. |
| 404 | not_found | Recurso inexistente. |
| 500 | internal_error | Falha nossa. O crédito é devolvido. |
| 503 | upstream_disabled | O serviço de dados está desligado. Nada é cobrado. |
| 503 | upstream_budget_exceeded | O limite de consultas do serviço de dados acabou por agora. Tente mais tarde. Nada é cobrado. |
| 503 | upstream_unavailable | O serviço de dados falhou, está ocupado ou a fila de buscas ao vivo está cheia. Tente de novo depois do tempo de Retry-After. Nada é cobrado. |
| 429 | contacts_daily_limit | Limite diário de consultas de contato da conta atingido (soma de todas as chaves). Veja Retry-After. Nada é cobrado. |
| 429 | miss_quota_exceeded | Cota de buscas novas por hora atingida, por chave e por conta (consultas já em cache não contam). Veja Retry-After. Nada é cobrado. |
| 429 | daily_spend_limit_exceeded | Limite diário de gasto da conta atingido (soma de todas as chaves; renova à meia-noite UTC). Veja Retry-After. Nada é cobrado. |
| 403 | terms_not_accepted | Os termos de uso da API não foram aceitos pelo dono da chave. Aceite no console. Nada é cobrado. |
Limites de taxa
Até 60 requisições por minuto e 10000 por dia, por chave. Há também um limite de 300 requisições por minuto por endereço IP, que vale inclusive para tentativas com chave errada. Ao exceder, a resposta é 429 com Retry-After.
Paginação e atualidade dos dados
As listas têm página de tamanho fixo em 10, com page de 1 a 50. A resposta traz pagination com page, pageSize, total e totalPages. O total é a contagem real de resultados, e totalPages nunca passa de 50, que é a última página que a API entrega (pedir a 51 é 400). Para chegar ao que está além dos 500 primeiros, refine por filtro e ordenação.
Toda resposta de dados traz meta.dataUpTo, o dia mais recente dos dados (a fonte tem um dia de atraso), e meta.currency, a moeda dos valores.
Sua primeira chamada
Consulte seu saldo. É gratuito:
curl 'https://developers.sendyx.com/v1/account/usage' \
-H "Authorization: Bearer $SENDYX_API_KEY"
const res = await fetch("https://developers.sendyx.com/v1/account/usage", {
method: "GET",
headers: { Authorization: `Bearer ${process.env.SENDYX_API_KEY}` },
});
if (!res.ok) {
const error = await res.json();
throw new Error(`${res.status} ${error.error}: ${error.message}`);
}
console.log(
"custo:", res.headers.get("x-credits-cost"),
"saldo:", res.headers.get("x-credits-remaining"),
);
const body = await res.json();
console.log(body);
import os
import requests
response = requests.get(
"https://developers.sendyx.com/v1/account/usage",
headers={"Authorization": f"Bearer {os.environ['SENDYX_API_KEY']}"},
)
response.raise_for_status()
print(
"custo:", response.headers.get("x-credits-cost"),
"saldo:", response.headers.get("x-credits-remaining"),
)
print(response.json())