Assinex Docs API v1

Documentação da API

API da Assinex

Compre assinaturas e produtos digitais automaticamente a partir do seu sistema. Consulte o catálogo com os seus preços, crie pedidos pagos com o saldo da carteira e entregue o acesso ao seu cliente pela resposta ou por webhook.

Base URLhttps://assinex.com/api/v1
AutenticaçãoAuthorization: Bearer <token>
FormatoJSON em UTF-8 · valores em BRL

Como uma venda funciona

  1. 1
    Saldo

    Você adiciona saldo por Pix no painel.

  2. 2
    Catálogo

    GET /products mostra preço e estoque.

  3. 3
    Pedido

    POST /orders debita o saldo e compra.

  4. 4
    Entrega

    O acesso vem na resposta ou no webhook.

#Primeiros passos

Em quatro passos você sai do cadastro para a primeira resposta da API.

  1. Crie a conta e adicione saldo

    Cadastre-se em assinex.com/cadastrar. No painel, abra Carteira › Adicionar saldo por Pix. O saldo entra assim que o pagamento é confirmado e é com ele que os pedidos são pagos.

  2. Crie um token de API

    Em Integração › Criar token, dê um nome (por exemplo, o nome do sistema) e copie o token na hora: ele começa com ax_live_ e aparece uma única vez. Cada conta pode ter até 10 tokens ativos.

    O token dá acesso ao seu saldo. Guarde em uma variável de ambiente do servidor. Nunca coloque no site, no app do celular ou no Git.

  3. Faça a primeira chamada

    Guarde o token no terminal e chame GET /me. Ele não altera nada e confirma que a autenticação funciona.

    Terminal
    # Troque pelo token criado no painel. Não salve no Git.
    export ASSINEX_TOKEN="ax_live_SEU_TOKEN"
    Requisição
    curl https://assinex.com/api/v1/me \
      -H "Authorization: Bearer $ASSINEX_TOKEN"
    // Rode no servidor (Node.js 18+, Bun, Deno, Edge Functions). Nunca no navegador.
    const response = await fetch("https://assinex.com/api/v1/me", {
      method: "GET",
      headers: {
        Authorization: `Bearer ${process.env.ASSINEX_TOKEN}`,
      },
    });
    const data = await response.json();
    
    if (!response.ok) {
      // data.error.code é estável; use-o para decidir o que fazer.
      throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
    }
    console.log(data);
    // npm install axios
    import axios from "axios";
    
    const assinex = axios.create({
      baseURL: "https://assinex.com/api/v1",
      headers: { Authorization: `Bearer ${process.env.ASSINEX_TOKEN}` },
      timeout: 30_000,
    });
    
    try {
      const { status, data } = await assinex.get("/me");
      console.log(status, data);
    } catch (error) {
      if (!error.response) throw error; // rede ou timeout
      const { code, message } = error.response.data.error;
      console.error(error.response.status, code, message);
    }
    <?php
    $ch = curl_init('https://assinex.com/api/v1/me');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . getenv('ASSINEX_TOKEN'),
        ],
        CURLOPT_TIMEOUT => 30,
    ]);
    $resposta = curl_exec($ch);
    if ($resposta === false) {
        throw new RuntimeException(curl_error($ch)); // rede
    }
    $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    
    $dados = json_decode($resposta, true);
    if ($status >= 400) {
        throw new RuntimeException($dados['error']['code'] . ': ' . $dados['error']['message']);
    }
    print_r($dados);
    # pip install requests
    import os
    import requests
    
    resposta = requests.get(
        "https://assinex.com/api/v1/me",
        headers={"Authorization": f"Bearer {os.environ['ASSINEX_TOKEN']}"},
        timeout=30,
    )
    dados = resposta.json()
    
    if not resposta.ok:
        erro = dados["error"]
        raise RuntimeError(f"{resposta.status_code} {erro['code']}: {erro['message']}")
    print(dados)
    // Java 11+
    import java.net.URI;
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    import java.time.Duration;
    
    public class Assinex {
        public static void main(String[] args) throws Exception {
            String token = System.getenv("ASSINEX_TOKEN");
            HttpRequest requisicao = HttpRequest.newBuilder()
                .uri(URI.create("https://assinex.com/api/v1/me"))
                .header("Authorization", "Bearer " + token)
                .timeout(Duration.ofSeconds(30))
                .GET()
                .build();
    
            HttpResponse<String> resposta = HttpClient.newHttpClient()
                .send(requisicao, HttpResponse.BodyHandlers.ofString());
            // 2xx: sucesso. 4xx e 5xx: o corpo traz { "error": { "code", "message" } }.
            System.out.println(resposta.statusCode());
            System.out.println(resposta.body());
        }
    }
  4. Interprete a resposta

    HTTP 200 com o id e o nome da sua conta significa que está tudo certo. Qualquer outra situação volta como erro, sempre no mesmo formato: use o code para decidir o que fazer e mostre a message só para pessoas.

    Resposta
    {
      "id": "acc_Z3k9QmX2pLr8Tw",
      "name": "Loja Exemplo",
      "status": "ativa",
      "created_at": "2026-09-30T12:00:00.000Z"
    }
    {
      "error": {
        "code": "token_invalido",
        "message": "Token ausente, inválido ou revogado. Envie Authorization: Bearer <token>."
      }
    }

#Integre com IA

Use o Cursor, o Claude, o ChatGPT ou outra IA para escrever a integração no seu sistema. O prompt abaixo traz a referência completa da API e as regras que evitam os erros mais comuns (token exposto, pedido cobrado duas vezes, webhook sem verificação).

Prompt de integração Referência completa da API, em português. Também em assinex.com/llms.txt.
Carregando o prompt… Se não aparecer, abra https://assinex.com/llms.txt e copie o conteúdo.

A ferramenta consegue abrir links? Então basta este pedido curto:

Pedido curto
Leia https://assinex.com/llms.txt e integre a API da Assinex ao meu projeto seguindo exatamente as regras desse arquivo. Antes de escrever código, me faça as perguntas indicadas nele.

Como usar em cada ferramenta

Cursor

  1. Jeito mais rápido: abra o chat (Ctrl+L, ou Cmd+L no Mac), escolha o modo Agent, cole o prompt e envie.
  2. Para o projeto inteiro lembrar das regras: crie o arquivo .cursor/rules/assinex.mdc na raiz do projeto e cole o prompt dentro.
  3. Como documentação indexada: em Cursor Settings, na área de Docs, adicione https://assinex.com/llms.txt. Depois escreva @Docs e escolha Assinex no chat.

Revise antes de publicar. Teste com GET /me e faça um pedido de valor baixo com um external_id de teste. Confirme que o token está só no servidor e que o webhook recusa assinaturas inválidas.

#Autenticação

Todas as rotas exigem um token de API no cabeçalho Authorization, no esquema Bearer. O token é criado no painel em Integração › Criar token, começa com ax_live_ e só aparece uma vez.

Cabeçalho
Authorization: Bearer ax_live_SEU_TOKEN
  • Cada token age em nome da conta que o criou: só enxerga o saldo, o catálogo e os pedidos dessa conta.
  • Token revogado no painel para de funcionar na hora. Crie um token por sistema; se um vazar, revogue só ele.
  • A API não usa cookies nem sessão do painel. Sem o cabeçalho, a resposta é 401 token_invalido.
  • Chame a API só a partir do seu servidor. Um token no navegador ou no app fica visível para qualquer pessoa.

#Base URL e ambientes

Todas as rotas ficam sob uma única base, sempre em HTTPS:

Produção
https://assinex.com/api/v1

Não existe ambiente de testes (sandbox). Toda chamada usa a sua conta real. As consultas (GET) não alteram nada. POST /orders compra de verdade e debita o saldo. Para testar a integração, use GET /me e GET /products e faça um pedido de valor baixo com um external_id de teste.

#Formato das respostas

ItemRegra
CorpoJSON em UTF-8, nas respostas e no corpo de POST (com Content-Type: application/json, até 16 KB).
ValoresNúmeros em reais (BRL), com duas casas decimais. Exemplo: 11.5 é R$ 11,50.
DatasTexto ISO 8601 em UTC, como 2026-09-30T12:00:00.000Z.
IdsTexto com prefixo: acc_ conta, prd_ produto, ord_ pedido, evt_ evento de webhook. Trate como texto opaco.
CacheToda resposta vem com Cache-Control: no-store.
ErrosStatus HTTP de erro com { "error": { "code", "message" } }. Veja Códigos de erro.

#Códigos de erro

Todo erro tem o mesmo formato. Use o code no seu sistema: ele é estável. A message é para pessoas e pode mudar.

HTTP/1.1 402 Payment Required
{
  "error": {
    "code": "saldo_insuficiente",
    "message": "Saldo insuficiente na carteira para esta compra."
  }
}

Como tratar

  • 4xx: a requisição foi recusada e nada foi cobrado. Corrija o pedido antes de repetir (exceto 429, que pede só para esperar).
  • 5xx ou falha de rede: repita a mesma requisição. Em POST /orders, com o mesmo external_id: não há cobrança dupla.

Todos os códigos

HTTPcodeQuando acontece
400external_id_invalidoexternal_id vazio, com mais de 100 caracteres ou com caracteres fora de letras, números e . _ : -.
400external_id_obrigatorioFaltou external_id.
400json_invalidoO corpo não é um JSON válido.
400product_id_obrigatorioFaltou product_id (ou o Content-Type).
400quantidade_invalidaquantity não é um inteiro entre 1 e max_per_order.
401token_invalidoToken ausente, errado ou revogado.
402saldo_insuficienteA carteira não cobre o total. Nada é cobrado.
403api_desativadaO acesso pela API foi desligado para esta conta.
403conta_suspensaA conta foi suspensa. Fale com a Assinex.
403limite_diario_excedidoO pedido passaria do limite de gasto diário da conta (horário de Brasília). Nada é cobrado.
404pedido_nao_encontradoO pedido não existe nesta conta (ou o id não tem o formato ord_…).
404produto_nao_encontradoO product_id não existe no catálogo.
404rota_nao_encontradaMétodo ou caminho que não existe na API.
409external_id_em_usoO external_id já foi usado com outro produto ou outra quantidade.
409produto_indisponivelSem estoque para a quantidade ou produto pausado. Tente mais tarde.
413corpo_grande_demaisO corpo passou de 16 KB.
429limite_de_requisicoesMais de 120 requisições por minuto no token, ou mais de 30 tentativas por minuto com token inválido no mesmo IP.
500erro_internoFalha do nosso lado. Repita a requisição; em POST /orders use o mesmo external_id.
503vendas_pausadasVendas pausadas temporariamente. Nada é cobrado; repita mais tarde com o mesmo external_id.

#Limites de requisição

LimiteValor
Requisições por token120 por minuto
Tentativas com token inválido30 por minuto por IP
Tokens ativos por conta10
Tamanho do corpo16 KB
Itens por página em GET /orders100

As respostas autenticadas trazem os cabeçalhos abaixo. Acima do limite, a resposta é 429 limite_de_requisicoes com Retry-After em segundos.

Cabeçalhos de limite
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
Retry-After: 23

A conta também pode ter um limite de gasto diário definido pela Assinex. Um pedido que passaria desse valor recebe 403 limite_diario_excedido, sem cobrança.

#Idempotência

O external_id de POST /orders é a chave do pedido na sua conta. Se a conexão cair ou vier um 500, repita exatamente a mesma requisição:

  • Mesmo external_id, mesmo produto e mesma quantidade: você recebe o pedido que já existe, com HTTP 200 e "idempotent_replay": true. Nada é cobrado de novo.
  • Mesmo external_id com outro produto ou outra quantidade: 409 external_id_em_uso.
  • Duas requisições iguais ao mesmo tempo geram um só pedido.

Use um id que já existe no seu sistema, como o número da venda (loja-1042). Não gere um id aleatório a cada tentativa, ou cada repetição vira uma compra nova.

#Paginação

Só GET /orders é paginado. Os pedidos vêm do mais novo para o mais antigo, até limit por página (padrão 50, máximo 100). Quando a página vem cheia, next traz um cursor; envie esse valor em before para a próxima página. next: null indica o fim.

cURL
# Primeira página
curl "https://assinex.com/api/v1/orders?limit=100" \
  -H "Authorization: Bearer $ASSINEX_TOKEN"
# { "data": [ ...100 pedidos... ], "next": "ord_3Fh8sK1pQw0LmZ" }

# Página seguinte: envie o next em before
curl "https://assinex.com/api/v1/orders?limit=100&before=ord_3Fh8sK1pQw0LmZ" \
  -H "Authorization: Bearer $ASSINEX_TOKEN"

GET /products devolve o catálogo inteiro de uma vez.

Referência

Endpoints

Seis operações, todas sob https://assinex.com/api/v1 e todas autenticadas. Os exemplos de cada uma estão em cURL, JavaScript, Node.js, PHP, Python e Java; a linguagem escolhida vale para a página inteira.

OperaçãoRota
Consultar a contaGET /me
Consultar o saldoGET /balance
Listar produtosGET /products
Criar pedidoPOST /orders
Consultar pedidoGET /orders/{id}
Listar pedidosGET /orders

Conta

#Consultar a conta

GEThttps://assinex.com/api/v1/me

Confirma que o token funciona e mostra a conta dona dele.

Use como primeira chamada da integração e como verificação de saúde: se responder 200, o token é válido e a conta está ativa.

Autenticação

Token de API no cabeçalho Authorization. A operação vale só para a conta dona do token. Veja Autenticação.

Cabeçalhos

Authorizationtextoobrigatório
Bearer seguido do seu token (ax_live_…).

Resposta 200 OK

idtexto
Id público da conta (acc_…).
nametexto
Nome da conta.
statustexto
Sempre ativa. Conta suspensa recebe 403 conta_suspensa.
created_atdata
Criação da conta, ISO 8601 em UTC.

Erros

Só os erros comuns de qualquer rota autenticada (401, 403, 429 e 500).

Requisição
curl https://assinex.com/api/v1/me \
  -H "Authorization: Bearer $ASSINEX_TOKEN"
// Rode no servidor (Node.js 18+, Bun, Deno, Edge Functions). Nunca no navegador.
const response = await fetch("https://assinex.com/api/v1/me", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.ASSINEX_TOKEN}`,
  },
});
const data = await response.json();

if (!response.ok) {
  // data.error.code é estável; use-o para decidir o que fazer.
  throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
}
console.log(data);
// npm install axios
import axios from "axios";

const assinex = axios.create({
  baseURL: "https://assinex.com/api/v1",
  headers: { Authorization: `Bearer ${process.env.ASSINEX_TOKEN}` },
  timeout: 30_000,
});

try {
  const { status, data } = await assinex.get("/me");
  console.log(status, data);
} catch (error) {
  if (!error.response) throw error; // rede ou timeout
  const { code, message } = error.response.data.error;
  console.error(error.response.status, code, message);
}
<?php
$ch = curl_init('https://assinex.com/api/v1/me');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('ASSINEX_TOKEN'),
    ],
    CURLOPT_TIMEOUT => 30,
]);
$resposta = curl_exec($ch);
if ($resposta === false) {
    throw new RuntimeException(curl_error($ch)); // rede
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

$dados = json_decode($resposta, true);
if ($status >= 400) {
    throw new RuntimeException($dados['error']['code'] . ': ' . $dados['error']['message']);
}
print_r($dados);
# pip install requests
import os
import requests

resposta = requests.get(
    "https://assinex.com/api/v1/me",
    headers={"Authorization": f"Bearer {os.environ['ASSINEX_TOKEN']}"},
    timeout=30,
)
dados = resposta.json()

if not resposta.ok:
    erro = dados["error"]
    raise RuntimeError(f"{resposta.status_code} {erro['code']}: {erro['message']}")
print(dados)
// Java 11+
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class Assinex {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("ASSINEX_TOKEN");
        HttpRequest requisicao = HttpRequest.newBuilder()
            .uri(URI.create("https://assinex.com/api/v1/me"))
            .header("Authorization", "Bearer " + token)
            .timeout(Duration.ofSeconds(30))
            .GET()
            .build();

        HttpResponse<String> resposta = HttpClient.newHttpClient()
            .send(requisicao, HttpResponse.BodyHandlers.ofString());
        // 2xx: sucesso. 4xx e 5xx: o corpo traz { "error": { "code", "message" } }.
        System.out.println(resposta.statusCode());
        System.out.println(resposta.body());
    }
}
Resposta
{
  "id": "acc_Z3k9QmX2pLr8Tw",
  "name": "Loja Exemplo",
  "status": "ativa",
  "created_at": "2026-09-30T12:00:00.000Z"
}
{
  "error": {
    "code": "token_invalido",
    "message": "Token ausente, inválido ou revogado. Envie Authorization: Bearer <token>."
  }
}

Carteira

#Consultar o saldo

GEThttps://assinex.com/api/v1/balance

Saldo disponível na carteira, em reais.

Os pedidos são pagos com este saldo. Para adicionar saldo, use Carteira › Adicionar saldo por Pix no painel: a API não cria cobranças.

Autenticação

Token de API no cabeçalho Authorization. A operação vale só para a conta dona do token. Veja Autenticação.

Cabeçalhos

Authorizationtextoobrigatório
Bearer seguido do seu token (ax_live_…).

Resposta 200 OK

balancenúmero
Saldo em reais, com duas casas decimais.
currencytexto
Sempre BRL.

Erros

Só os erros comuns de qualquer rota autenticada (401, 403, 429 e 500).

Requisição
curl https://assinex.com/api/v1/balance \
  -H "Authorization: Bearer $ASSINEX_TOKEN"
// Rode no servidor (Node.js 18+, Bun, Deno, Edge Functions). Nunca no navegador.
const response = await fetch("https://assinex.com/api/v1/balance", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.ASSINEX_TOKEN}`,
  },
});
const data = await response.json();

if (!response.ok) {
  // data.error.code é estável; use-o para decidir o que fazer.
  throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
}
console.log(data);
// npm install axios
import axios from "axios";

const assinex = axios.create({
  baseURL: "https://assinex.com/api/v1",
  headers: { Authorization: `Bearer ${process.env.ASSINEX_TOKEN}` },
  timeout: 30_000,
});

try {
  const { status, data } = await assinex.get("/balance");
  console.log(status, data);
} catch (error) {
  if (!error.response) throw error; // rede ou timeout
  const { code, message } = error.response.data.error;
  console.error(error.response.status, code, message);
}
<?php
$ch = curl_init('https://assinex.com/api/v1/balance');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('ASSINEX_TOKEN'),
    ],
    CURLOPT_TIMEOUT => 30,
]);
$resposta = curl_exec($ch);
if ($resposta === false) {
    throw new RuntimeException(curl_error($ch)); // rede
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

$dados = json_decode($resposta, true);
if ($status >= 400) {
    throw new RuntimeException($dados['error']['code'] . ': ' . $dados['error']['message']);
}
print_r($dados);
# pip install requests
import os
import requests

resposta = requests.get(
    "https://assinex.com/api/v1/balance",
    headers={"Authorization": f"Bearer {os.environ['ASSINEX_TOKEN']}"},
    timeout=30,
)
dados = resposta.json()

if not resposta.ok:
    erro = dados["error"]
    raise RuntimeError(f"{resposta.status_code} {erro['code']}: {erro['message']}")
print(dados)
// Java 11+
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class Assinex {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("ASSINEX_TOKEN");
        HttpRequest requisicao = HttpRequest.newBuilder()
            .uri(URI.create("https://assinex.com/api/v1/balance"))
            .header("Authorization", "Bearer " + token)
            .timeout(Duration.ofSeconds(30))
            .GET()
            .build();

        HttpResponse<String> resposta = HttpClient.newHttpClient()
            .send(requisicao, HttpResponse.BodyHandlers.ofString());
        // 2xx: sucesso. 4xx e 5xx: o corpo traz { "error": { "code", "message" } }.
        System.out.println(resposta.statusCode());
        System.out.println(resposta.body());
    }
}
Resposta
{
  "balance": 138.5,
  "currency": "BRL"
}

Catálogo

#Listar produtos

GEThttps://assinex.com/api/v1/products

Catálogo com o seu preço, estoque e limite por pedido.

Lista todo o catálogo de uma vez (sem paginação), já com o seu preço. Guarde o id: é ele que vai em product_id ao criar um pedido.

O estoque muda o tempo todo. Consulte antes de vender e trate available: false como temporário.

Autenticação

Token de API no cabeçalho Authorization. A operação vale só para a conta dona do token. Veja Autenticação.

Cabeçalhos

Authorizationtextoobrigatório
Bearer seguido do seu token (ax_live_…).

Resposta 200 OK

data[].idtexto
Id do produto (prd_…).
data[].nametexto
Nome do produto.
data[].descriptiontexto ou null
Descrição, quando houver.
data[].pricenúmero ou null
Seu preço unitário em reais. null quando ainda não há preço para a sua conta.
data[].currencytexto
Sempre BRL.
data[].availablebooleano
Se dá para comprar agora.
data[].stockinteiro
Unidades em estoque neste momento.
data[].max_per_orderinteiro
Máximo de unidades em um pedido.
data[].imagetexto ou null
Caminho da imagem no domínio da Assinex (relativo, por exemplo /media/catalog/prd_….webp?v=2).
data[].marktexto ou null
Emoji que identifica o produto, quando houver.

Erros

Só os erros comuns de qualquer rota autenticada (401, 403, 429 e 500).

Requisição
curl https://assinex.com/api/v1/products \
  -H "Authorization: Bearer $ASSINEX_TOKEN"
// Rode no servidor (Node.js 18+, Bun, Deno, Edge Functions). Nunca no navegador.
const response = await fetch("https://assinex.com/api/v1/products", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.ASSINEX_TOKEN}`,
  },
});
const data = await response.json();

if (!response.ok) {
  // data.error.code é estável; use-o para decidir o que fazer.
  throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
}
console.log(data);
// npm install axios
import axios from "axios";

const assinex = axios.create({
  baseURL: "https://assinex.com/api/v1",
  headers: { Authorization: `Bearer ${process.env.ASSINEX_TOKEN}` },
  timeout: 30_000,
});

try {
  const { status, data } = await assinex.get("/products");
  console.log(status, data);
} catch (error) {
  if (!error.response) throw error; // rede ou timeout
  const { code, message } = error.response.data.error;
  console.error(error.response.status, code, message);
}
<?php
$ch = curl_init('https://assinex.com/api/v1/products');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('ASSINEX_TOKEN'),
    ],
    CURLOPT_TIMEOUT => 30,
]);
$resposta = curl_exec($ch);
if ($resposta === false) {
    throw new RuntimeException(curl_error($ch)); // rede
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

$dados = json_decode($resposta, true);
if ($status >= 400) {
    throw new RuntimeException($dados['error']['code'] . ': ' . $dados['error']['message']);
}
print_r($dados);
# pip install requests
import os
import requests

resposta = requests.get(
    "https://assinex.com/api/v1/products",
    headers={"Authorization": f"Bearer {os.environ['ASSINEX_TOKEN']}"},
    timeout=30,
)
dados = resposta.json()

if not resposta.ok:
    erro = dados["error"]
    raise RuntimeError(f"{resposta.status_code} {erro['code']}: {erro['message']}")
print(dados)
// Java 11+
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class Assinex {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("ASSINEX_TOKEN");
        HttpRequest requisicao = HttpRequest.newBuilder()
            .uri(URI.create("https://assinex.com/api/v1/products"))
            .header("Authorization", "Bearer " + token)
            .timeout(Duration.ofSeconds(30))
            .GET()
            .build();

        HttpResponse<String> resposta = HttpClient.newHttpClient()
            .send(requisicao, HttpResponse.BodyHandlers.ofString());
        // 2xx: sucesso. 4xx e 5xx: o corpo traz { "error": { "code", "message" } }.
        System.out.println(resposta.statusCode());
        System.out.println(resposta.body());
    }
}
Resposta
{
  "data": [
    {
      "id": "prd_Kd8Xq2mLp0Za1w",
      "name": "Assinatura digital 18 meses",
      "description": null,
      "price": 11.5,
      "currency": "BRL",
      "available": true,
      "stock": 277,
      "max_per_order": 50,
      "image": "/media/catalog/prd_Kd8Xq2mLp0Za1w.webp?v=2",
      "mark": null
    }
  ]
}

Pedidos

#Criar pedido

POSThttps://assinex.com/api/v1/orders

Compra um produto com o saldo da carteira.

O valor é debitado da carteira quando o pedido é criado. Na maioria das vezes a resposta já traz o acesso ("status": "entregue"). Se vier processando, espere o webhook ou consulte o pedido.

O external_id torna a chamada idempotente: repetir a mesma requisição devolve o mesmo pedido, com HTTP 200 e "idempotent_replay": true, sem cobrar de novo. Veja Idempotência.

Altera dados reais. Cria um pedido real e debita o valor do seu saldo. Não existe ambiente de testes.

Autenticação

Token de API no cabeçalho Authorization. A operação vale só para a conta dona do token. Veja Autenticação.

Cabeçalhos

Authorizationtextoobrigatório
Bearer seguido do seu token (ax_live_…).
Content-Typetextoobrigatório
application/json. Sem ele o corpo é ignorado e a resposta é product_id_obrigatorio.

Corpo da requisição

product_idtextoobrigatório
O id de GET /products.
external_idtextoobrigatório
Um id seu, único por pedido (por exemplo, o número da venda na sua loja). De 1 a 100 caracteres: letras, números e . _ : -.
quantityinteiroopcional
Padrão 1. De 1 até o max_per_order do produto.

Resposta 201 Created

orderobjeto
O pedido. Veja o objeto pedido.
idempotent_replaybooleano
true quando o external_id já existia e o pedido devolvido é o mesmo de antes (HTTP 200). false num pedido novo (HTTP 201).

Erros

HTTPcodeQuando acontece
400product_id_obrigatorioFaltou product_id (ou o Content-Type).
400external_id_obrigatorioFaltou external_id.
400external_id_invalidoexternal_id vazio, com mais de 100 caracteres ou com caracteres fora de letras, números e . _ : -.
400quantidade_invalidaquantity não é um inteiro entre 1 e max_per_order.
400json_invalidoO corpo não é um JSON válido.
402saldo_insuficienteA carteira não cobre o total. Nada é cobrado.
403limite_diario_excedidoO pedido passaria do limite de gasto diário da conta (horário de Brasília). Nada é cobrado.
404produto_nao_encontradoO product_id não existe no catálogo.
409produto_indisponivelSem estoque para a quantidade ou produto pausado. Tente mais tarde.
409external_id_em_usoO external_id já foi usado com outro produto ou outra quantidade.
413corpo_grande_demaisO corpo passou de 16 KB.
503vendas_pausadasVendas pausadas temporariamente. Nada é cobrado; repita mais tarde com o mesmo external_id.

Também podem ocorrer os erros comuns de qualquer rota autenticada (401, 403, 429 e 500).

Requisição
curl -X POST https://assinex.com/api/v1/orders \
  -H "Authorization: Bearer $ASSINEX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": "prd_Kd8Xq2mLp0Za1w",
    "quantity": 1,
    "external_id": "loja-1042"
  }'
// Rode no servidor (Node.js 18+, Bun, Deno, Edge Functions). Nunca no navegador.
const response = await fetch("https://assinex.com/api/v1/orders", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ASSINEX_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    product_id: "prd_Kd8Xq2mLp0Za1w",
    quantity: 1,
    external_id: "loja-1042",
  }),
});
const data = await response.json();

if (!response.ok) {
  // data.error.code é estável; use-o para decidir o que fazer.
  throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
}
console.log(data);
// npm install axios
import axios from "axios";

const assinex = axios.create({
  baseURL: "https://assinex.com/api/v1",
  headers: { Authorization: `Bearer ${process.env.ASSINEX_TOKEN}` },
  timeout: 30_000,
});

try {
  const { status, data } = await assinex.post("/orders", {
    product_id: "prd_Kd8Xq2mLp0Za1w",
    quantity: 1,
    external_id: "loja-1042",
  });
  console.log(status, data);
} catch (error) {
  if (!error.response) throw error; // rede ou timeout: repita com o mesmo external_id
  const { code, message } = error.response.data.error;
  console.error(error.response.status, code, message);
}
<?php
$ch = curl_init('https://assinex.com/api/v1/orders');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('ASSINEX_TOKEN'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'product_id' => 'prd_Kd8Xq2mLp0Za1w',
        'quantity' => 1,
        'external_id' => 'loja-1042',
    ]),
    CURLOPT_TIMEOUT => 30,
]);
$resposta = curl_exec($ch);
if ($resposta === false) {
    throw new RuntimeException(curl_error($ch)); // rede: repita com o mesmo external_id
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

$dados = json_decode($resposta, true);
if ($status >= 400) {
    throw new RuntimeException($dados['error']['code'] . ': ' . $dados['error']['message']);
}
print_r($dados);
# pip install requests
import os
import requests

resposta = requests.post(
    "https://assinex.com/api/v1/orders",
    headers={"Authorization": f"Bearer {os.environ['ASSINEX_TOKEN']}"},
    json={
        "product_id": "prd_Kd8Xq2mLp0Za1w",
        "quantity": 1,
        "external_id": "loja-1042",
    },
    timeout=30,
)
dados = resposta.json()

if not resposta.ok:
    erro = dados["error"]
    raise RuntimeError(f"{resposta.status_code} {erro['code']}: {erro['message']}")
print(dados)
// Java 11+
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class Assinex {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("ASSINEX_TOKEN");
        String corpo = "{\"product_id\":\"prd_Kd8Xq2mLp0Za1w\",\"quantity\":1,\"external_id\":\"loja-1042\"}";
        HttpRequest requisicao = HttpRequest.newBuilder()
            .uri(URI.create("https://assinex.com/api/v1/orders"))
            .header("Authorization", "Bearer " + token)
            .header("Content-Type", "application/json")
            .timeout(Duration.ofSeconds(30))
            .POST(HttpRequest.BodyPublishers.ofString(corpo))
            .build();

        HttpResponse<String> resposta = HttpClient.newHttpClient()
            .send(requisicao, HttpResponse.BodyHandlers.ofString());
        // 2xx: sucesso. 4xx e 5xx: o corpo traz { "error": { "code", "message" } }.
        System.out.println(resposta.statusCode());
        System.out.println(resposta.body());
    }
}
Resposta
{
  "order": {
    "id": "ord_7Qx2kP9mLsT1aB",
    "external_id": "loja-1042",
    "product_id": "prd_Kd8Xq2mLp0Za1w",
    "product_name": "Assinatura digital 18 meses",
    "quantity": 1,
    "unit_price": 11.5,
    "total": 11.5,
    "currency": "BRL",
    "status": "entregue",
    "delivery": {
      "items": [
        {
          "type": "link",
          "link": "https://exemplo.com/ativar/x8Kq",
          "instructions": "Abra o link e conclua o resgate na conta em que você quer o benefício. Faça isso logo após a entrega: alguns links expiram."
        }
      ],
      "text": "Link: https://exemplo.com/ativar/x8Kq\nComo usar: Abra o link e conclua o resgate na conta em que você quer o benefício. Faça isso logo após a entrega: alguns links expiram."
    },
    "error": null,
    "refunded": false,
    "created_at": "2026-09-30T12:00:00.000Z",
    "delivered_at": "2026-09-30T12:00:02.000Z",
    "updated_at": "2026-09-30T12:00:02.000Z"
  },
  "idempotent_replay": false
}
{
  "error": {
    "code": "saldo_insuficiente",
    "message": "Saldo insuficiente na carteira para esta compra."
  }
}
{
  "error": {
    "code": "external_id_em_uso",
    "message": "Esta external_id já foi usada em outro pedido com produto ou quantidade diferentes."
  }
}

Pedidos

#Consultar pedido

GEThttps://assinex.com/api/v1/orders/{id}

Um pedido da sua conta, pelo id da Assinex.

Use para acompanhar um pedido processando quando você não usa webhooks. Consulte a cada 10 a 30 segundos.

Autenticação

Token de API no cabeçalho Authorization. A operação vale só para a conta dona do token. Veja Autenticação.

Parâmetros de caminho

idtextoobrigatório
Id do pedido (ord_…), devolvido ao criar o pedido.

Cabeçalhos

Authorizationtextoobrigatório
Bearer seguido do seu token (ax_live_…).

Resposta 200 OK

orderobjeto
O pedido. Veja o objeto pedido.

Erros

HTTPcodeQuando acontece
404pedido_nao_encontradoO pedido não existe nesta conta (ou o id não tem o formato ord_…).

Também podem ocorrer os erros comuns de qualquer rota autenticada (401, 403, 429 e 500).

Requisição
curl https://assinex.com/api/v1/orders/ord_7Qx2kP9mLsT1aB \
  -H "Authorization: Bearer $ASSINEX_TOKEN"
// Rode no servidor (Node.js 18+, Bun, Deno, Edge Functions). Nunca no navegador.
const response = await fetch("https://assinex.com/api/v1/orders/ord_7Qx2kP9mLsT1aB", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.ASSINEX_TOKEN}`,
  },
});
const data = await response.json();

if (!response.ok) {
  // data.error.code é estável; use-o para decidir o que fazer.
  throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
}
console.log(data);
// npm install axios
import axios from "axios";

const assinex = axios.create({
  baseURL: "https://assinex.com/api/v1",
  headers: { Authorization: `Bearer ${process.env.ASSINEX_TOKEN}` },
  timeout: 30_000,
});

try {
  const { status, data } = await assinex.get("/orders/ord_7Qx2kP9mLsT1aB");
  console.log(status, data);
} catch (error) {
  if (!error.response) throw error; // rede ou timeout
  const { code, message } = error.response.data.error;
  console.error(error.response.status, code, message);
}
<?php
$ch = curl_init('https://assinex.com/api/v1/orders/ord_7Qx2kP9mLsT1aB');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('ASSINEX_TOKEN'),
    ],
    CURLOPT_TIMEOUT => 30,
]);
$resposta = curl_exec($ch);
if ($resposta === false) {
    throw new RuntimeException(curl_error($ch)); // rede
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

$dados = json_decode($resposta, true);
if ($status >= 400) {
    throw new RuntimeException($dados['error']['code'] . ': ' . $dados['error']['message']);
}
print_r($dados);
# pip install requests
import os
import requests

resposta = requests.get(
    "https://assinex.com/api/v1/orders/ord_7Qx2kP9mLsT1aB",
    headers={"Authorization": f"Bearer {os.environ['ASSINEX_TOKEN']}"},
    timeout=30,
)
dados = resposta.json()

if not resposta.ok:
    erro = dados["error"]
    raise RuntimeError(f"{resposta.status_code} {erro['code']}: {erro['message']}")
print(dados)
// Java 11+
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class Assinex {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("ASSINEX_TOKEN");
        HttpRequest requisicao = HttpRequest.newBuilder()
            .uri(URI.create("https://assinex.com/api/v1/orders/ord_7Qx2kP9mLsT1aB"))
            .header("Authorization", "Bearer " + token)
            .timeout(Duration.ofSeconds(30))
            .GET()
            .build();

        HttpResponse<String> resposta = HttpClient.newHttpClient()
            .send(requisicao, HttpResponse.BodyHandlers.ofString());
        // 2xx: sucesso. 4xx e 5xx: o corpo traz { "error": { "code", "message" } }.
        System.out.println(resposta.statusCode());
        System.out.println(resposta.body());
    }
}
Resposta
{
  "order": {
    "id": "ord_7Qx2kP9mLsT1aB",
    "external_id": "loja-1042",
    "product_id": "prd_Kd8Xq2mLp0Za1w",
    "product_name": "Assinatura digital 18 meses",
    "quantity": 1,
    "unit_price": 11.5,
    "total": 11.5,
    "currency": "BRL",
    "status": "entregue",
    "delivery": {
      "items": [
        {
          "type": "link",
          "link": "https://exemplo.com/ativar/x8Kq",
          "instructions": "Abra o link e conclua o resgate na conta em que você quer o benefício. Faça isso logo após a entrega: alguns links expiram."
        }
      ],
      "text": "Link: https://exemplo.com/ativar/x8Kq\nComo usar: Abra o link e conclua o resgate na conta em que você quer o benefício. Faça isso logo após a entrega: alguns links expiram."
    },
    "error": null,
    "refunded": false,
    "created_at": "2026-09-30T12:00:00.000Z",
    "delivered_at": "2026-09-30T12:00:02.000Z",
    "updated_at": "2026-09-30T12:00:02.000Z"
  }
}
{
  "error": {
    "code": "pedido_nao_encontrado",
    "message": "Pedido não encontrado."
  }
}

Pedidos

#Listar pedidos

GEThttps://assinex.com/api/v1/orders

Pedidos da conta, do mais novo para o mais antigo. Busca por external_id.

Para achar um pedido pelo seu id, filtre por external_id. Sem filtros, devolve os pedidos mais recentes primeiro.

A paginação usa cursor: quando a página vem cheia, next traz o id do último pedido; envie esse valor em before para buscar a página seguinte. next: null indica a última página. Veja Paginação.

Autenticação

Token de API no cabeçalho Authorization. A operação vale só para a conta dona do token. Veja Autenticação.

Parâmetros de consulta

external_idtextoopcional
O seu id do pedido. Valor fora do formato devolve 400 external_id_invalido.
statustextoopcional
processando, entregue ou falhou. Outros valores são ignorados.Valores: processando entregue falhou
limitinteiroopcional
De 1 a 100. Padrão 50.
beforetextoopcional
Cursor: o valor de next da página anterior.

Cabeçalhos

Authorizationtextoobrigatório
Bearer seguido do seu token (ax_live_…).

Resposta 200 OK

datalista
Pedidos no formato do objeto pedido.
nexttexto ou null
Cursor da próxima página, ou null.

Erros

HTTPcodeQuando acontece
400external_id_invalidoexternal_id fora do formato aceito.

Também podem ocorrer os erros comuns de qualquer rota autenticada (401, 403, 429 e 500).

Requisição
curl "https://assinex.com/api/v1/orders?external_id=loja-1042" \
  -H "Authorization: Bearer $ASSINEX_TOKEN"
// Rode no servidor (Node.js 18+, Bun, Deno, Edge Functions). Nunca no navegador.
const response = await fetch("https://assinex.com/api/v1/orders?external_id=loja-1042", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.ASSINEX_TOKEN}`,
  },
});
const data = await response.json();

if (!response.ok) {
  // data.error.code é estável; use-o para decidir o que fazer.
  throw new Error(`${response.status} ${data.error.code}: ${data.error.message}`);
}
console.log(data);
// npm install axios
import axios from "axios";

const assinex = axios.create({
  baseURL: "https://assinex.com/api/v1",
  headers: { Authorization: `Bearer ${process.env.ASSINEX_TOKEN}` },
  timeout: 30_000,
});

try {
  const { status, data } = await assinex.get("/orders", { params: { external_id: "loja-1042" } });
  console.log(status, data);
} catch (error) {
  if (!error.response) throw error; // rede ou timeout
  const { code, message } = error.response.data.error;
  console.error(error.response.status, code, message);
}
<?php
$ch = curl_init('https://assinex.com/api/v1/orders?' . http_build_query([
    'external_id' => 'loja-1042',
]));
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('ASSINEX_TOKEN'),
    ],
    CURLOPT_TIMEOUT => 30,
]);
$resposta = curl_exec($ch);
if ($resposta === false) {
    throw new RuntimeException(curl_error($ch)); // rede
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

$dados = json_decode($resposta, true);
if ($status >= 400) {
    throw new RuntimeException($dados['error']['code'] . ': ' . $dados['error']['message']);
}
print_r($dados);
# pip install requests
import os
import requests

resposta = requests.get(
    "https://assinex.com/api/v1/orders",
    headers={"Authorization": f"Bearer {os.environ['ASSINEX_TOKEN']}"},
    params={
        "external_id": "loja-1042",
    },
    timeout=30,
)
dados = resposta.json()

if not resposta.ok:
    erro = dados["error"]
    raise RuntimeError(f"{resposta.status_code} {erro['code']}: {erro['message']}")
print(dados)
// Java 11+
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class Assinex {
    public static void main(String[] args) throws Exception {
        String token = System.getenv("ASSINEX_TOKEN");
        HttpRequest requisicao = HttpRequest.newBuilder()
            .uri(URI.create("https://assinex.com/api/v1/orders?external_id=loja-1042"))
            .header("Authorization", "Bearer " + token)
            .timeout(Duration.ofSeconds(30))
            .GET()
            .build();

        HttpResponse<String> resposta = HttpClient.newHttpClient()
            .send(requisicao, HttpResponse.BodyHandlers.ofString());
        // 2xx: sucesso. 4xx e 5xx: o corpo traz { "error": { "code", "message" } }.
        System.out.println(resposta.statusCode());
        System.out.println(resposta.body());
    }
}
Resposta
{
  "data": [
    {
      "id": "ord_7Qx2kP9mLsT1aB",
      "external_id": "loja-1042",
      "product_id": "prd_Kd8Xq2mLp0Za1w",
      "product_name": "Assinatura digital 18 meses",
      "quantity": 1,
      "unit_price": 11.5,
      "total": 11.5,
      "currency": "BRL",
      "status": "entregue",
      "delivery": {
        "items": [
          {
            "type": "link",
            "link": "https://exemplo.com/ativar/x8Kq",
            "instructions": "Abra o link e conclua o resgate na conta em que você quer o benefício. Faça isso logo após a entrega: alguns links expiram."
          }
        ],
        "text": "Link: https://exemplo.com/ativar/x8Kq\nComo usar: Abra o link e conclua o resgate na conta em que você quer o benefício. Faça isso logo após a entrega: alguns links expiram."
      },
      "error": null,
      "refunded": false,
      "created_at": "2026-09-30T12:00:00.000Z",
      "delivered_at": "2026-09-30T12:00:02.000Z",
      "updated_at": "2026-09-30T12:00:02.000Z"
    }
  ],
  "next": null
}
{
  "error": {
    "code": "external_id_invalido",
    "message": "external_id inválido."
  }
}

Objetos

#O objeto pedido

É o que vem em order (criar e consultar), em cada item de data (listar) e em data.order dos webhooks.

idtexto
Id do pedido na Assinex (ord_…).
external_idtexto
O seu id, enviado ao criar.
product_idtexto
Id do produto (prd_…).
product_nametexto
Nome do produto no momento da compra.
quantityinteiro
Unidades compradas.
unit_pricenúmero
Preço unitário cobrado, em reais.
totalnúmero
Total debitado da carteira.
currencytexto
Sempre BRL.
statustexto
processando, entregue ou falhou. Veja Situação do pedido.
deliveryobjeto ou null
O acesso entregue. Só vem com status: entregue. Veja Entrega.
errorobjeto ou null
Com status: falhou: { code, message } explicando o motivo.
refundedbooleano
true quando o valor voltou para a carteira.
created_atdata
Criação do pedido (ISO 8601, UTC).
delivered_atdata ou null
Quando o acesso foi liberado.
updated_atdata
Última mudança no pedido.

#Situação do pedido

statusSignificadoO que fazer
processandoPago com a carteira; o acesso está sendo liberado.Espere o webhook ou consulte a cada 10 a 30 segundos.
entregueO acesso está em delivery.Repasse ao seu cliente.
falhouA compra não pôde ser concluída. O motivo está em error; refunded: true indica que o valor voltou para a carteira.Crie outro pedido com outro external_id, se quiser tentar de novo.

Um pedido nunca sai de entregue, e só é estornado quando há certeza de que a compra não aconteceu.

#Entrega

delivery.items traz um item por unidade comprada. O campo type diz a forma do acesso, e instructions é o como usar: mostre esse texto ao seu cliente junto com o acesso, sem trocar os passos.

typeQuandoCampos
accountConta prontalogin, password, instructions e, se houver, totp (código ou link do 2FA)
linkLink para resgatarlink e instructions
codeCódigo de resgatecode e instructions
textOutro formatocontent (texto livre) e, quando houver, link, code e instructions

delivery.text junta tudo com rótulos (Login:, Senha:, Link:…) e termina com a linha Como usar:. É o mesmo conteúdo do arquivo .txt baixado no painel, pronto para uma mensagem. Quando o item é uma conta, use login e password: o texto cru da conta não vem na resposta.

Item do tipo account (exemplo)
{
  "type": "account",
  "login": "[email protected]",
  "password": "segredo123",
  "instructions": "Entre em https://account.microsoft.com com o e-mail e a senha entregues. No primeiro acesso, troque a senha. O plano já está nessa conta."
}

Webhooks

#Eventos

Configure a URL em Integração › Webhook. Ela precisa ser https e pública. Ao salvar pela primeira vez, você recebe um segredo whsec_… que aparece uma única vez; dá para gerar outro no mesmo lugar.

EventoQuandodata
pedido.entregueO acesso foi liberado.{ "order": … }
pedido.falhouA compra não saiu e o valor foi estornado.{ "order": … }
testeBotão Enviar teste no painel.{ "message": "Evento de teste da Assinex." }

Cada evento é um POST com estes cabeçalhos e corpo (data.order segue o objeto pedido):

Cabeçalhos
POST /sua-url HTTP/1.1
Content-Type: application/json
User-Agent: Assinex-Webhooks/1.0
X-Assinex-Event: pedido.entregue
X-Assinex-Delivery: evt_Hn2Lq8rVx1Ck9d
X-Assinex-Timestamp: 1790769602
X-Assinex-Signature: sha256=5f1c…
Corpo (exemplo)
{
  "id": "evt_Hn2Lq8rVx1Ck9d",
  "type": "pedido.entregue",
  "created_at": "2026-09-30T12:00:02.000Z",
  "data": {
    "order": {
      "id": "ord_7Qx2kP9mLsT1aB",
      "external_id": "loja-1042",
      "product_id": "prd_Kd8Xq2mLp0Za1w",
      "product_name": "Assinatura digital 18 meses",
      "quantity": 1,
      "unit_price": 11.5,
      "total": 11.5,
      "currency": "BRL",
      "status": "entregue",
      "delivery": {
        "items": [
          {
            "type": "link",
            "link": "https://exemplo.com/ativar/x8Kq",
            "instructions": "Abra o link e conclua o resgate na conta em que você quer o benefício. Faça isso logo após a entrega: alguns links expiram."
          }
        ],
        "text": "Link: https://exemplo.com/ativar/x8Kq\nComo usar: Abra o link e conclua o resgate na conta em que você quer o benefício. Faça isso logo após a entrega: alguns links expiram."
      },
      "error": null,
      "refunded": false,
      "created_at": "2026-09-30T12:00:00.000Z",
      "delivered_at": "2026-09-30T12:00:02.000Z",
      "updated_at": "2026-09-30T12:00:02.000Z"
    }
  }
}
{
  "id": "evt_Pq4Ws9tYc2Hm5n",
  "type": "pedido.falhou",
  "created_at": "2026-09-30T12:04:10.000Z",
  "data": {
    "order": {
      "id": "ord_7Qx2kP9mLsT1aB",
      "external_id": "loja-1042",
      "product_id": "prd_Kd8Xq2mLp0Za1w",
      "product_name": "Assinatura digital 18 meses",
      "quantity": 1,
      "unit_price": 11.5,
      "total": 11.5,
      "currency": "BRL",
      "status": "falhou",
      "delivery": null,
      "error": {
        "code": "produto_indisponivel",
        "message": "Produto indisponível no momento."
      },
      "refunded": true,
      "created_at": "2026-09-30T12:00:00.000Z",
      "delivered_at": null,
      "updated_at": "2026-09-30T12:04:10.000Z"
    }
  }
}
{
  "id": "evt_Lm3Rt7uVb0Nx4q",
  "type": "teste",
  "created_at": "2026-09-30T12:10:00.000Z",
  "data": {
    "message": "Evento de teste da Assinex."
  }
}

Entrega e novas tentativas

Responda com qualquer 2xx em até 10 segundos. Sem 2xx, tentamos de novo em 1 minuto, 5 minutos, 15 minutos, 1 hora, 3 horas, 6 horas e 12 horas (8 tentativas no total). Pelo painel dá para ver cada envio e reenviar. Use o id do evento (o mesmo de X-Assinex-Delivery) para ignorar repetições.

#Verificar a assinatura

Calcule o HMAC-SHA256 do texto {X-Assinex-Timestamp}.{corpo bruto} com o seu segredo e compare com o valor depois de sha256=, em tempo constante. Use o corpo exatamente como chegou, antes de converter para JSON, e recuse eventos com timestamp de mais de 5 minutos.

Verificação
import crypto from "node:crypto";

// corpoBruto: o corpo exatamente como chegou (texto), antes do JSON.parse.
export function assinaturaValida(corpoBruto, cabecalhos, segredo) {
  const ts = cabecalhos["x-assinex-timestamp"];
  const recebido = String(cabecalhos["x-assinex-signature"] || "").replace("sha256=", "");
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const esperado = crypto.createHmac("sha256", segredo).update(`${ts}.${corpoBruto}`).digest("hex");
  return recebido.length === esperado.length &&
    crypto.timingSafeEqual(Buffer.from(recebido), Buffer.from(esperado));
}
<?php
$corpo = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_ASSINEX_TIMESTAMP'] ?? '';
$recebido = str_replace('sha256=', '', $_SERVER['HTTP_X_ASSINEX_SIGNATURE'] ?? '');
$esperado = hash_hmac('sha256', $ts . '.' . $corpo, getenv('ASSINEX_WEBHOOK_SECRET'));
if (abs(time() - (int) $ts) > 300 || !hash_equals($esperado, $recebido)) {
    http_response_code(400);
    exit;
}
$evento = json_decode($corpo, true);
http_response_code(200);
import hmac, hashlib, time

def assinatura_valida(corpo_bruto: bytes, cabecalhos, segredo: str) -> bool:
    ts = cabecalhos.get("X-Assinex-Timestamp", "")
    recebido = cabecalhos.get("X-Assinex-Signature", "").replace("sha256=", "")
    if abs(time.time() - int(ts or 0)) > 300:
        return False
    esperado = hmac.new(segredo.encode(), f"{ts}.".encode() + corpo_bruto, hashlib.sha256).hexdigest()
    return hmac.compare_digest(esperado, recebido)

Ferramentas

#Playground

Envie requisições reais à API sem sair da página. Escolha o endpoint, informe o seu token e veja a resposta, o status e o tempo.

Ambiente real. Não existe sandbox: as chamadas usam a sua conta. Consultas não alteram nada; POST /orders compra de verdade e só é enviado depois da sua confirmação.

GEThttps://assinex.com/api/v1/me

Fica só na memória desta aba e vai apenas para /api/v1 deste site. Não é salvo nem aparece no cURL copiado.

Cabeçalhos enviados
Resposta
Envie uma requisição para ver a resposta aqui.

O playground precisa de JavaScript. Use os exemplos em cURL de cada endpoint.

#Exemplo de integração

Uma função completa para vender um produto: cria o pedido com o número da venda como external_id, repete com segurança em falhas de rede, 429 e 5xx, e devolve a entrega quando ela vem na resposta. Se o pedido ficar processando, a entrega chega pelo webhook pedido.entregue.

Vender um produto
// Rode no servidor. Node.js 18+ (fetch nativo), Bun ou Deno.
const API = "https://assinex.com/api/v1";
const esperar = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

export async function venderProduto(numeroDaVenda, productId, quantidade = 1) {
  const corpo = JSON.stringify({
    product_id: productId,
    quantity: quantidade,
    external_id: `venda-${numeroDaVenda}`, // o mesmo em toda tentativa
  });

  for (let tentativa = 1; tentativa <= 4; tentativa++) {
    let resposta;
    try {
      resposta = await fetch(`${API}/orders`, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${process.env.ASSINEX_TOKEN}`,
          "Content-Type": "application/json",
        },
        body: corpo,
        signal: AbortSignal.timeout(30_000),
      });
    } catch {
      await esperar(2_000 * tentativa); // rede ou timeout: repete igual
      continue;
    }

    if (resposta.status === 429 || resposta.status >= 500) {
      const segundos = Number(resposta.headers.get("Retry-After")) || 2 * tentativa;
      await esperar(segundos * 1_000);
      continue;
    }

    const dados = await resposta.json();
    if (!resposta.ok) {
      // 4xx: nada foi cobrado. Ex.: saldo_insuficiente, produto_indisponivel.
      throw new Error(`${dados.error.code}: ${dados.error.message}`);
    }

    const { order } = dados;
    if (order.status === "entregue") return order.delivery; // mostre delivery.items ao cliente
    if (order.status === "processando") return null; // chega no webhook pedido.entregue
    throw new Error(`Pedido ${order.id} falhou: ${order.error?.message}`);
  }
  throw new Error("Assinex indisponível agora. Tente depois com o mesmo número de venda.");
}
<?php
// Requer a extensão curl.
function venderProduto(string $numeroDaVenda, string $productId, int $quantidade = 1): ?array
{
    $corpo = json_encode([
        'product_id' => $productId,
        'quantity' => $quantidade,
        'external_id' => 'venda-' . $numeroDaVenda, // o mesmo em toda tentativa
    ]);

    for ($tentativa = 1; $tentativa <= 4; $tentativa++) {
        $ch = curl_init('https://assinex.com/api/v1/orders');
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $corpo,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . getenv('ASSINEX_TOKEN'),
                'Content-Type: application/json',
            ],
            CURLOPT_TIMEOUT => 30,
        ]);
        $resposta = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);

        if ($resposta === false || $status === 429 || $status >= 500) {
            sleep(2 * $tentativa); // repete igual: não há cobrança dupla
            continue;
        }

        $dados = json_decode($resposta, true);
        if ($status >= 400) {
            // 4xx: nada foi cobrado. Ex.: saldo_insuficiente, produto_indisponivel.
            throw new RuntimeException($dados['error']['code'] . ': ' . $dados['error']['message']);
        }

        $pedido = $dados['order'];
        if ($pedido['status'] === 'entregue') {
            return $pedido['delivery']; // mostre delivery.items ao cliente
        }
        if ($pedido['status'] === 'processando') {
            return null; // chega no webhook pedido.entregue
        }
        throw new RuntimeException('Pedido ' . $pedido['id'] . ' falhou: ' . ($pedido['error']['message'] ?? ''));
    }
    throw new RuntimeException('Assinex indisponível agora. Tente depois com o mesmo número de venda.');
}
# pip install requests
import os
import time
import requests

API = "https://assinex.com/api/v1"

def vender_produto(numero_da_venda: str, product_id: str, quantidade: int = 1):
    corpo = {
        "product_id": product_id,
        "quantity": quantidade,
        "external_id": f"venda-{numero_da_venda}",  # o mesmo em toda tentativa
    }
    cabecalhos = {"Authorization": f"Bearer {os.environ['ASSINEX_TOKEN']}"}

    for tentativa in range(1, 5):
        try:
            resposta = requests.post(f"{API}/orders", json=corpo, headers=cabecalhos, timeout=30)
        except requests.RequestException:
            time.sleep(2 * tentativa)  # rede ou timeout: repete igual
            continue

        if resposta.status_code == 429 or resposta.status_code >= 500:
            time.sleep(int(resposta.headers.get("Retry-After", 2 * tentativa)))
            continue

        dados = resposta.json()
        if not resposta.ok:
            # 4xx: nada foi cobrado. Ex.: saldo_insuficiente, produto_indisponivel.
            erro = dados["error"]
            raise RuntimeError(f"{erro['code']}: {erro['message']}")

        pedido = dados["order"]
        if pedido["status"] == "entregue":
            return pedido["delivery"]  # mostre delivery["items"] ao cliente
        if pedido["status"] == "processando":
            return None  # chega no webhook pedido.entregue
        raise RuntimeError(f"Pedido {pedido['id']} falhou: {(pedido.get('error') or {}).get('message')}")

    raise RuntimeError("Assinex indisponível agora. Tente depois com o mesmo número de venda.")

#Boas práticas

  • Use o número da venda da sua loja como external_id. Em qualquer dúvida (timeout, erro 500), repita a mesma requisição.
  • Guarde o token e o segredo do webhook em variáveis de ambiente do servidor. Nunca no site, no app ou no Git.
  • Crie um token por sistema. Se um vazar, revogue só ele.
  • Verifique a assinatura de todo webhook e ignore eventos repetidos pelo id.
  • Confira GET /balance antes de campanhas grandes e mantenha saldo para as vendas do dia.
  • Trate produto_indisponivel como temporário: avise o seu cliente e tente mais tarde.
  • Decida pelo error.code, nunca pelo texto de error.message.

Precisa de ajuda com a integração? Entre no painel, onde ficam os seus pedidos, os eventos de webhook, os tokens e o suporte.