Documentação
Três modelos, um endpoint, formato compatível com a OpenAI. Se já tens código a falar com a API deles, muda o URL e a chave — o resto fica igual.
Introdução#
A API Nexi expõe os mesmos três modelos que servem o chat. Um único endpoint, POST https://api.nexichat.ai/v1/chat/{marca}, onde a marca é air, prime ou nova.
O corpo e a resposta seguem o formato chat completions da OpenAI. Na prática: os SDKs oficiais deles funcionam apontando o base_url para aqui.
model no corpo. Se mandares esse campo, é ignorado — não é erro, mas também não muda nada.Primeiro pedido#
Cria uma chave na consola e faz a chamada. Não é preciso instalar nada.
curl https://api.nexichat.ai/v1/chat/prime \
-H "Authorization: Bearer nexi_live_..." \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role": "user", "content": "Olá!"}]
}'A resposta:
{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1786500000,
"model": "nexi-prime-v1",
"choices": [{
"index": 0,
"message": { "role": "assistant", "content": "Olá! Em que posso ajudar?" },
"finish_reason": "stop"
}],
"usage": { "prompt_tokens": 12, "completion_tokens": 8, "total_tokens": 20 }
}Autenticação#
Cabeçalho Authorization: Bearer nexi_live_… em todos os pedidos.
A chave é mostrada uma única vez, quando a crias. Depois disso só se vê o prefixo — se a perderes, a única saída é revogar e criar outra. Podes ter várias em simultâneo, o que torna a rotação indolor: cria a nova, troca no teu código, revoga a velha.
Modelos e preços#
Preços em euros por milhão de tokens. Sem mensalidade — pagas o que usas.
| Modelo | URL | Entrada | Saída |
|---|---|---|---|
Nexi Air Respostas rápidas, classificação, tarefas simples. nexi-air-v1 | /chat/air | 0,25 € | 0,70 € |
Nexi Prime O equilibrado. Textos longos, análise, programação. nexi-prime-v1 | /chat/prime | 0,45 € | 0,90 € |
Nexi Nova Raciocínio. Problemas difíceis, matemática, planeamento. nexi-nova-v1 | /chat/nova | 1,49 € | 4,99 € |
Os tokens de raciocínio do Nova contam como saída — é assim que o uso é reportado, e é também por isso que ele é o mais caro dos três.
O pedido#
POST https://api.nexichat.ai/v1/chat/{air|prime|nova} com corpo JSON.
| Campo | Notas |
|---|---|
messagesarrayobrigatório | De 1 a 200 mensagens. Cada uma tem role e content. |
streamboolean | Predefinido false. A true, a resposta vem em SSE. |
toolsarray | Até 64 funções que o modelo pode pedir para executares. |
max_tokensinteger | Teto de tokens gerados. Sem isto, usa o máximo do modelo. |
temperaturenumber | De 0 a 2. Mais baixo é mais determinístico; 0 para classificação e extração. |
Mensagens#
Quatro papéis, e cada um tem uma forma própria.
| role | Forma | Para quê |
|---|---|---|
system | content | As instruções. A identidade Nexi vai sempre à frente das tuas. |
user | content | O que a pessoa escreveu. |
assistant | content e/ou tool_calls | Respostas anteriores. É assim que se dá histórico ao modelo. |
tool | content + tool_call_id | O resultado de uma função que executaste. |
Cada mensagem aceita até 200 000 caracteres. A conversa é stateless: mandas o histórico todo em cada pedido, e nada fica guardado do lado da Nexi.
A resposta#
O texto está em choices[0].message.content. O usage traz a contagem de tokens — é por ele que o custo é calculado, e bate certo com o que aparece na consola.
| finish_reason | Significa |
|---|---|
stop | O modelo terminou por si. |
length | Bateu no max_tokens. A resposta está cortada a meio. |
tool_calls | Está à espera que executes uma função. |
x-request-id. Regista-o nos teus logs: é por ele que o suporte encontra o pedido exato, e sem ele um "falhou ontem à tarde" é impossível de investigar.Streaming#
Com "stream": true a resposta é SSE: linhas data: com o mesmo formato da OpenAI e data: [DONE] no fim. O texto vem em choices[0].delta.content.
data: {"object":"chat.completion.chunk",
"choices":[{"index":0,"delta":{"content":"Olá"}}]}
data: {"object":"chat.completion.chunk",
"choices":[{"index":0,"delta":{"content":"!"}}]}
data: [DONE]curl https://api.nexichat.ai/v1/chat/nova \
-H "Authorization: Bearer nexi_live_..." \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role": "user", "content": "Explica a relatividade"}],
"stream": true
}' --no-buffer--no-buffer no curl, stream=True no requests). Sem isso recebes tudo de uma vez no fim e o streaming não serve de nada — que é a queixa nº1 de quem integra SSE pela primeira vez.Ferramentas#
O modelo pode pedir que executes funções tuas. São três passos, e o do meio é teu: a API nunca executa nada — devolve o pedido, tu corres a função e mandas o resultado de volta.
curl https://api.nexichat.ai/v1/chat/prime \
-H "Authorization: Bearer nexi_live_..." \
-H "Content-Type: application/json" \
-d '{
"messages": [{"role": "user", "content": "Que tempo faz no Porto?"}],
"tools": [{
"type": "function",
"function": {
"name": "meteorologia",
"description": "Tempo atual numa cidade",
"parameters": {
"type": "object",
"properties": {"cidade": {"type": "string"}},
"required": ["cidade"]
}
}
}]
}'tool_call tem de receber a sua resposta role: "tool", com o tool_call_id a bater certo. Um histórico com a chamada mas sem o resultado é rejeitado — e a partir daí a conversa inteira falha, não só essa mensagem.Listar modelos#
GET https://api.nexichat.ai/v1/models devolve a lista no formato da OpenAI. Útil para preencher um seletor sem os nomes ficarem escritos à mão no teu código.
{
"object": "list",
"data": [
{ "id": "nexi-air-v1", "object": "model", "owned_by": "nexichat" },
{ "id": "nexi-prime-v1", "object": "model", "owned_by": "nexichat" },
{ "id": "nexi-nova-v1", "object": "model", "owned_by": "nexichat" }
]
}Erros#
Sempre o mesmo formato. O code é estável e serve para ramificar no teu código; a message é para humanos e pode mudar sem aviso.
{
"error": {
"code": "rate_limit_rpm",
"message": "Rate limit exceeded for your tier."
}
}| HTTP | code | Quando acontece |
|---|---|---|
| 400 | invalid_request | O corpo não passou a validação. A mensagem diz qual o campo. |
| 400 | tools_unsupported | Mandaste tools a um modelo que não as suporta. |
| 401 | invalid_api_key | Chave em falta, malformada ou revogada. |
| 402 | insufficient_balance | Saldo esgotado. Carrega na consola. |
| 404 | unknown_model | A marca no URL não é air, prime nem nova. |
| 429 | rate_limit_rpm | Pedidos por minuto acima do teu tier. |
| 429 | rate_limit_tpm | Tokens por minuto acima do teu tier. |
| 429 | daily_spend_limit_reached | Bateste no teto diário definido na consola. |
| 502 | upstream_error | O modelo falhou. Repetir costuma resolver. |
| 503 | model_unavailable | Modelo temporariamente indisponível. |
Os 429 e o 502 valem a pena repetir com recuo exponencial. Os 4xx restantes não — repetir um invalid_request dá sempre o mesmo resultado.
Limites#
O tier sobe sozinho com o total carregado. Não há formulário nem espera.
| Tier | Requisito | Pedidos/min | Tokens/min |
|---|---|---|---|
| 1 | inicial | 10 | 10 000 |
| 2 | 10 € carregados | 100 | 200 000 |
| 3 | 100 € carregados | 500 | 1 000 000 |
Podes ainda definir um teto de gasto diário na consola. Ao atingi-lo, a API devolve daily_spend_limit_reached até ao dia seguinte — é uma rede contra um ciclo infinito no teu código, não um limite comercial.
Boas práticas#
| Faz | Porquê |
|---|---|
| Guarda o x-request-id | Sem ele, investigar um pedido que falhou há dois dias é impossível. |
| Recuo exponencial nos 429 | Repetir de imediato só agrava — e conta para o limite outra vez. |
| Teto de gasto diário | Um ciclo infinito no teu código custa dinheiro real até alguém reparar. |
| Uma chave por ambiente | Revogar a de testes não pode derrubar produção. |
| Air para o que é simples | Classificar, extrair e resumir não precisam do Nova. A diferença de preço é de 6×. |