Referência
Clientes
A ficha dos clientes e a sua conta corrente. Um cliente «Especial» tem conta corrente, desconto e limite de crédito; um cliente que não escolher é o «Consumidor Final».
A ficha dos clientes e a sua conta corrente. Um cliente «Especial» tem conta corrente, desconto e limite de crédito; um cliente que não escolher é o «Consumidor Final».
| Operação | O que faz |
|---|---|
GET /api/clientes | Lista os clientes, por ordem alfabética. |
GET /api/clientes/{id} | A ficha completa de um cliente. |
GET /api/clientes/{id}/extracto | O extracto da conta corrente de um cliente: cada débito (factura a crédito) e crédito (recibo, nota de crédito), com o documento e o saldo depois do movimento. |
GET /api/clientes/{id}/resumo | O resumo de compras de um cliente: o total comprado, o número de documentos e o que está em dívida. |
POST /api/clientes | Cria um cliente. |
PUT /api/clientes/{id} | Actualiza a ficha de um cliente. |
DELETE /api/clientes/{id} | Elimina um cliente da lista. |
GET /api/clientes/{id}/extracto/pdf | O extracto de conta de um cliente em PDF. |
POST /api/clientes/{id}/extracto/enviar | Envia o extracto de conta ao cliente por e-mail. |
POST /api/clientes/{id}/movimentos | Regista um movimento manual na conta corrente de um cliente (um ajuste ou um acerto). |
/api/clientes#Lista os clientes, por ordem alfabética.
filtro procura no nome, no número de contribuinte, no telefone, no telemóvel e no e-mail. Os clientes eliminados não aparecem. Com alteradoDesde (data e hora ISO 8601 em UTC) só vêm os criados ou alterados desde esse instante, por ordem de alteração, e os eliminados aparecem marcados (eliminado: true): ver Sincronização incremental.
A resposta é uma página: itens e proximoCursor. Ver Paginação.
Parâmetros
| Nome | Onde | Tipo | Obrigatório |
|---|---|---|---|
filtro | na pesquisa | texto | |
cursor | na pesquisa | texto | |
tamanho | na pesquisa | número inteiro | |
alteradoDesde | na pesquisa | data e hora (ISO 8601) |
Resposta (200 · JSON)
| Campo | Tipo | Significado |
|---|---|---|
itens | lista de objectos | Os registos desta página. |
itens[].id | identificador (UUID) | Identificador único (UUID). |
itens[].nome | texto | O nome. |
itens[].numeroContribuinte | texto ou nulo | O número de contribuinte (NIF). |
itens[].telefone | texto ou nulo | O telefone. |
itens[].especial | verdadeiro/falso | Cliente com conta corrente (desconto e limite de crédito). |
itens[].saldoAtual | número | A dívida actual do cliente (conta corrente). |
itens[].isProtegido | verdadeiro/falso | Verdadeiro no «Consumidor Final», que não se altera nem se elimina. |
itens[].alteradoEmUtc | data e hora (ISO 8601) | |
itens[].eliminado | verdadeiro/falso | |
proximoCursor | texto ou nulo | O cursor da página seguinte; nulo quando não há mais. Ver Paginação. |
Exemplo
Listar clientes (página de 2)
curl 'https://<endereço-da-API>/api/clientes?tamanho=2' \
-H 'X-Api-Key: assw_v1_<chave>'
const resposta = await fetch('https://<endereço-da-API>/api/clientes?tamanho=2', {
method: 'GET',
headers: {
"X-Api-Key": "assw_v1_<chave>"
},
})
const dados = await resposta.json()
import requests
resposta = requests.get(
'https://<endereço-da-API>/api/clientes?tamanho=2',
headers={
'X-Api-Key': 'assw_v1_<chave>'
},
)
dados = resposta.json()
using var cliente = new HttpClient { BaseAddress = new Uri("https://<endereço-da-API>") };
using var pedido = new HttpRequestMessage(HttpMethod.Get, "/api/clientes?tamanho=2");
pedido.Headers.Add("X-Api-Key", "assw_v1_<chave>");
using var resposta = await cliente.SendAsync(pedido);
var texto = await resposta.Content.ReadAsStringAsync();
200 OK Resposta
content-type: application/json; charset=utf-8
x-mucanda-api-version: 1
{
"itens": [
{
"id": "01a12201-fa2a-7eec-8bcb-2f0b5e02bb8e",
"nome": "Ana Beatriz Kiala",
"numeroContribuinte": "004512987LA041",
"telefone": "925112233",
"especial": false,
"saldoAtual": 0,
"isProtegido": false
},
{
"id": "01a12201-fa49-7e89-af00-dde77cab4010",
"nome": "Cantina do Mercado Velho",
"numeroContribuinte": "5417220318",
"telefone": "928667788",
"especial": false,
"saldoAtual": 0,
"isProtegido": false
}
],
"proximoCursor": "Q2FudGluYSBkbyBNZXJjYWRvIFZlbGhvIDAxYTEyMjAxLWZhNDktN2U4OS1hZjAwLWRkZTc3Y2FiNDAxMA=="
}
/api/clientes/{id}#A ficha completa de um cliente.
Parâmetros
| Nome | Onde | Tipo | Obrigatório |
|---|---|---|---|
id | no caminho | identificador (UUID) | sim |
Resposta (200 · JSON)
| Campo | Tipo | Significado |
|---|---|---|
id | identificador (UUID) | Identificador único (UUID). |
nome | texto | O nome. |
endereco | texto | A morada. |
numeroContribuinte | texto ou nulo | O número de contribuinte (NIF). |
isConsumidorFinal | verdadeiro/falso | Verdadeiro no cliente sem identificação fiscal. |
telefone | texto ou nulo | O telefone. |
telemovel | texto ou nulo | O telemóvel. |
fax | texto ou nulo | |
email | texto ou nulo | O endereço de e-mail. |
website | texto ou nulo | |
especial | verdadeiro/falso | Cliente com conta corrente (desconto e limite de crédito). |
pvpPreferido | texto ou nulo | |
condicaoPagamentoId | identificador (UUID) ou nulo | |
desconto | número ou nulo | O desconto habitual do cliente, em percentagem. |
limiteCredito | número ou nulo | O limite de crédito (cliente com conta corrente). |
observacao | texto ou nulo | O texto livre. |
taxaRetencaoId | identificador (UUID) ou nulo | |
municipioId | identificador (UUID) ou nulo | |
enviarAlertas | verdadeiro/falso | |
enviarDocumentos | verdadeiro/falso | |
saldoAtual | número | A dívida actual do cliente (conta corrente). |
isProtegido | verdadeiro/falso | Verdadeiro no «Consumidor Final», que não se altera nem se elimina. |
pessoaSingular | verdadeiro/falso |
Erros específicos
NAO_ENCONTRADO — além dos gerais.
Exemplo
Obter um cliente
curl 'https://<endereço-da-API>/api/clientes/01a12f69-98f8-7688-85b9-8d829c101c8b' \
-H 'X-Api-Key: assw_v1_<chave>'
const resposta = await fetch('https://<endereço-da-API>/api/clientes/01a12f69-98f8-7688-85b9-8d829c101c8b', {
method: 'GET',
headers: {
"X-Api-Key": "assw_v1_<chave>"
},
})
const dados = await resposta.json()
import requests
resposta = requests.get(
'https://<endereço-da-API>/api/clientes/01a12f69-98f8-7688-85b9-8d829c101c8b',
headers={
'X-Api-Key': 'assw_v1_<chave>'
},
)
dados = resposta.json()
using var cliente = new HttpClient { BaseAddress = new Uri("https://<endereço-da-API>") };
using var pedido = new HttpRequestMessage(HttpMethod.Get, "/api/clientes/01a12f69-98f8-7688-85b9-8d829c101c8b");
pedido.Headers.Add("X-Api-Key", "assw_v1_<chave>");
using var resposta = await cliente.SendAsync(pedido);
var texto = await resposta.Content.ReadAsStringAsync();
200 OK Resposta
content-type: application/json; charset=utf-8
x-mucanda-api-version: 1
{
"id": "01a12f69-98f8-7688-85b9-8d829c101c8b",
"nome": "Mercearia Cazenga Nova",
"endereco": "Rua 5, Cazenga, Luanda",
"numeroContribuinte": "5520879633",
"isConsumidorFinal": false,
"telefone": null,
"telemovel": "926000111",
"fax": null,
"email": "compras@mercearia-cazenga.example",
"website": null,
"especial": false,
"pvpPreferido": null,
"condicaoPagamentoId": null,
"desconto": null,
"limiteCredito": null,
"observacao": null,
"taxaRetencaoId": null,
"municipioId": null,
"enviarAlertas": false,
"enviarDocumentos": true,
"saldoAtual": 0,
"isProtegido": false
}
/api/clientes/{id}/extracto#O extracto da conta corrente de um cliente: cada débito (factura a crédito) e crédito (recibo, nota de crédito), com o documento e o saldo depois do movimento.
A resposta é uma página: itens e proximoCursor. Ver Paginação.
Parâmetros
| Nome | Onde | Tipo | Obrigatório |
|---|---|---|---|
id | no caminho | identificador (UUID) | sim |
cursor | na pesquisa | texto | |
tamanho | na pesquisa | número inteiro |
Resposta (200 · JSON)
| Campo | Tipo | Significado |
|---|---|---|
itens | lista de objectos | Os registos desta página. |
itens[].id | identificador (UUID) | Identificador único (UUID). |
itens[].data | data e hora (ISO 8601) | A data e hora (UTC). |
itens[].valor | número | O valor. |
itens[].tipo | texto | |
itens[].documento | texto ou nulo | |
itens[].saldoAposMovimento | número | O saldo depois deste movimento. |
proximoCursor | texto ou nulo | O cursor da página seguinte; nulo quando não há mais. Ver Paginação. |
Pedido
curl 'https://<endereço-da-API>/api/clientes/<id>/extracto' \
-H 'X-Api-Key: <a-sua-chave>'
/api/clientes/{id}/resumo#O resumo de compras de um cliente: o total comprado, o número de documentos e o que está em dívida.
Parâmetros
| Nome | Onde | Tipo | Obrigatório |
|---|---|---|---|
id | no caminho | identificador (UUID) | sim |
Resposta (200 · JSON)
| Campo | Tipo |
|---|---|
totalComprado | número |
documentos | número inteiro |
emDivida | número |
Pedido
curl 'https://<endereço-da-API>/api/clientes/<id>/resumo' \
-H 'X-Api-Key: <a-sua-chave>'
/api/clientes#Cria um cliente.
nome e endereco são obrigatórios. numeroContribuinte não pode repetir-se na empresa (erro DUPLICADO).
Para um cliente com conta corrente envie especial: true com limiteCredito (e, se quiser, desconto).
Aceita Idempotency-Key: repetir o pedido com a mesma chave devolve o cliente já criado, sem o duplicar.
Corpo do pedido (JSON · CreateClienteCommand)
| Campo | Tipo | Obrigatório | Significado |
|---|---|---|---|
nome | texto | sim | O nome. |
endereco | texto | sim | A morada. |
numeroContribuinte | texto ou nulo | O número de contribuinte (NIF). | |
isConsumidorFinal | verdadeiro/falso | sim | Verdadeiro no cliente sem identificação fiscal. |
email | texto ou nulo | O endereço de e-mail. | |
telefone | texto ou nulo | O telefone. | |
telemovel | texto ou nulo | O telemóvel. | |
fax | texto ou nulo | ||
website | texto ou nulo | ||
municipioId | identificador (UUID) ou nulo | ||
taxaRetencaoId | identificador (UUID) ou nulo | ||
enviarAlertas | verdadeiro/falso | sim | |
enviarDocumentos | verdadeiro/falso | sim | |
observacao | texto ou nulo | O texto livre. | |
especial | verdadeiro/falso | sim | Cliente com conta corrente (desconto e limite de crédito). |
pvpPreferido | uma de: «Pvp1», «Pvp2», «Pvp3», «Pvp4», «null» ou nulo | ||
condicaoPagamentoId | identificador (UUID) ou nulo | ||
desconto | número ou nulo | O desconto habitual do cliente, em percentagem. | |
limiteCredito | número ou nulo | O limite de crédito (cliente com conta corrente). | |
pessoaSingular | verdadeiro/falso |
Resposta
Devolve 201 com o identificador do cliente criado: { "id": "…" }.
Erros específicos
DUPLICADO · ERRO_DE_VALIDACAO · IDEMPOTENCIA_CONFLITO — além dos gerais.
Exemplo
Criar um cliente (com Idempotency-Key)
curl -X POST 'https://<endereço-da-API>/api/clientes' \
-H 'Idempotency-Key: b2a756b8-b776-4fd1-9af3-ba4e60f115f3' \
-H 'X-Api-Key: assw_v1_<chave>' \
-H 'Content-Type: application/json' \
-d '{
"nome": "Mercearia Cazenga Nova",
"endereco": "Rua 5, Cazenga, Luanda",
"numeroContribuinte": "5520879633",
"isConsumidorFinal": false,
"email": "compras@mercearia-cazenga.example",
"telefone": null,
"telemovel": "926000111",
"fax": null,
"website": null,
"municipioId": null,
"taxaRetencaoId": null,
"enviarAlertas": false,
"enviarDocumentos": true,
"observacao": null,
"especial": false,
"pvpPreferido": "Pvp1",
"condicaoPagamentoId": null,
"desconto": null,
"limiteCredito": null
}'
const resposta = await fetch('https://<endereço-da-API>/api/clientes', {
method: 'POST',
headers: {
"Idempotency-Key": "b2a756b8-b776-4fd1-9af3-ba4e60f115f3",
"X-Api-Key": "assw_v1_<chave>",
"Content-Type": "application/json"
},
body: JSON.stringify({
"nome": "Mercearia Cazenga Nova",
"endereco": "Rua 5, Cazenga, Luanda",
"numeroContribuinte": "5520879633",
"isConsumidorFinal": false,
"email": "compras@mercearia-cazenga.example",
"telefone": null,
"telemovel": "926000111",
"fax": null,
"website": null,
"municipioId": null,
"taxaRetencaoId": null,
"enviarAlertas": false,
"enviarDocumentos": true,
"observacao": null,
"especial": false,
"pvpPreferido": "Pvp1",
"condicaoPagamentoId": null,
"desconto": null,
"limiteCredito": null
}),
})
const dados = await resposta.json()
import requests
resposta = requests.post(
'https://<endereço-da-API>/api/clientes',
headers={
'Idempotency-Key': 'b2a756b8-b776-4fd1-9af3-ba4e60f115f3',
'X-Api-Key': 'assw_v1_<chave>',
'Content-Type': 'application/json'
},
json={
'nome': 'Mercearia Cazenga Nova',
'endereco': 'Rua 5, Cazenga, Luanda',
'numeroContribuinte': '5520879633',
'isConsumidorFinal': False,
'email': 'compras@mercearia-cazenga.example',
'telefone': None,
'telemovel': '926000111',
'fax': None,
'website': None,
'municipioId': None,
'taxaRetencaoId': None,
'enviarAlertas': False,
'enviarDocumentos': True,
'observacao': None,
'especial': False,
'pvpPreferido': 'Pvp1',
'condicaoPagamentoId': None,
'desconto': None,
'limiteCredito': None
},
)
dados = resposta.json()
using var cliente = new HttpClient { BaseAddress = new Uri("https://<endereço-da-API>") };
using var pedido = new HttpRequestMessage(HttpMethod.Post, "/api/clientes");
pedido.Headers.Add("Idempotency-Key", "b2a756b8-b776-4fd1-9af3-ba4e60f115f3");
pedido.Headers.Add("X-Api-Key", "assw_v1_<chave>");
pedido.Content = new StringContent("""
{
"nome": "Mercearia Cazenga Nova",
"endereco": "Rua 5, Cazenga, Luanda",
"numeroContribuinte": "5520879633",
"isConsumidorFinal": false,
"email": "compras@mercearia-cazenga.example",
"telefone": null,
"telemovel": "926000111",
"fax": null,
"website": null,
"municipioId": null,
"taxaRetencaoId": null,
"enviarAlertas": false,
"enviarDocumentos": true,
"observacao": null,
"especial": false,
"pvpPreferido": "Pvp1",
"condicaoPagamentoId": null,
"desconto": null,
"limiteCredito": null
}
""", Encoding.UTF8, "application/json");
using var resposta = await cliente.SendAsync(pedido);
var texto = await resposta.Content.ReadAsStringAsync();
201 Created Resposta
content-type: application/json; charset=utf-8
x-mucanda-api-version: 1
location: /api/clientes/01a12f69-98f8-7688-85b9-8d829c101c8b
{
"id": "01a12f69-98f8-7688-85b9-8d829c101c8b"
}
/api/clientes/{id}#Actualiza a ficha de um cliente.
Substitui a ficha inteira: o que não for enviado fica sem valor. O caminho certo é ler o cliente (GET), alterar o que precisa e enviar todos os campos.
O cliente «Consumidor Final» é protegido e não se altera.
Parâmetros
| Nome | Onde | Tipo | Obrigatório |
|---|---|---|---|
id | no caminho | identificador (UUID) | sim |
Corpo do pedido (JSON · UpdateClienteRequest)
| Campo | Tipo | Obrigatório | Significado |
|---|---|---|---|
nome | texto | sim | O nome. |
endereco | texto | sim | A morada. |
numeroContribuinte | texto ou nulo | O número de contribuinte (NIF). | |
isConsumidorFinal | verdadeiro/falso | sim | Verdadeiro no cliente sem identificação fiscal. |
email | texto ou nulo | O endereço de e-mail. | |
telefone | texto ou nulo | O telefone. | |
telemovel | texto ou nulo | O telemóvel. | |
fax | texto ou nulo | ||
website | texto ou nulo | ||
municipioId | identificador (UUID) ou nulo | ||
taxaRetencaoId | identificador (UUID) ou nulo | ||
enviarAlertas | verdadeiro/falso | sim | |
enviarDocumentos | verdadeiro/falso | sim | |
observacao | texto ou nulo | O texto livre. | |
especial | verdadeiro/falso | sim | Cliente com conta corrente (desconto e limite de crédito). |
pvpPreferido | uma de: «Pvp1», «Pvp2», «Pvp3», «Pvp4», «null» ou nulo | ||
condicaoPagamentoId | identificador (UUID) ou nulo | ||
desconto | número ou nulo | O desconto habitual do cliente, em percentagem. | |
limiteCredito | número ou nulo | O limite de crédito (cliente com conta corrente). | |
pessoaSingular | verdadeiro/falso |
Resposta
Devolve 204 sem corpo.
Erros específicos
DUPLICADO · NAO_ENCONTRADO — além dos gerais.
Pedido
curl -X PUT 'https://<endereço-da-API>/api/clientes/<id>' \
-H 'X-Api-Key: <a-sua-chave>' \
-H 'Content-Type: application/json' \
-d '{
"nome": "texto",
"endereco": "texto",
"isConsumidorFinal": false,
"enviarAlertas": false,
"enviarDocumentos": false,
"especial": false
}'
/api/clientes/{id}#Elimina um cliente da lista.
O cliente deixa de aparecer, mas o histórico não se apaga: os documentos já emitidos mantêm o cliente tal como estava.
O «Consumidor Final» não se elimina.
Parâmetros
| Nome | Onde | Tipo | Obrigatório |
|---|---|---|---|
id | no caminho | identificador (UUID) | sim |
Resposta
Devolve 204 sem corpo.
Pedido
curl -X DELETE 'https://<endereço-da-API>/api/clientes/<id>' \
-H 'X-Api-Key: <a-sua-chave>'
/api/clientes/{id}/extracto/pdf#O extracto de conta de um cliente em PDF.
de e ate (dias, hora legal de Angola) limitam o período. É o extracto do ledger do cliente.
Parâmetros
| Nome | Onde | Tipo | Obrigatório |
|---|---|---|---|
id | no caminho | identificador (UUID) | sim |
de | na pesquisa | data (AAAA-MM-DD) | |
ate | na pesquisa | data (AAAA-MM-DD) |
Resposta
Devolve 200 com o ficheiro PDF (application/pdf).
Pedido
curl 'https://<endereço-da-API>/api/clientes/<id>/extracto/pdf' \
-H 'X-Api-Key: <a-sua-chave>'
/api/clientes/{id}/extracto/enviar#Envia o extracto de conta ao cliente por e-mail.
Não é idempotente: repetir envia outro e-mail.
Parâmetros
| Nome | Onde | Tipo | Obrigatório |
|---|---|---|---|
id | no caminho | identificador (UUID) | sim |
Corpo do pedido (JSON · EnviarExtractoRequest)
| Campo | Tipo | Obrigatório |
|---|---|---|
de | data (AAAA-MM-DD) ou nulo | |
ate | data (AAAA-MM-DD) ou nulo | |
destinatario | texto ou nulo |
Pedido
curl -X POST 'https://<endereço-da-API>/api/clientes/<id>/extracto/enviar' \
-H 'X-Api-Key: <a-sua-chave>' \
-H 'Idempotency-Key: <um-GUID-novo>' \
-H 'Content-Type: application/json' \
-d '{}'
/api/clientes/{id}/movimentos#Regista um movimento manual na conta corrente de um cliente (um ajuste ou um acerto).
O extracto só se acrescenta: um erro corrige-se com um movimento contrário.
Parâmetros
| Nome | Onde | Tipo | Obrigatório |
|---|---|---|---|
id | no caminho | identificador (UUID) | sim |
Corpo do pedido (JSON · RegistarMovimentoRequest)
| Campo | Tipo | Obrigatório | Significado |
|---|---|---|---|
data | data e hora (ISO 8601) | sim | A data e hora (UTC). |
valor | número | sim | O valor. |
tipo | uma de: «Debito», «Credito» | sim | |
documento | texto ou nulo |
Pedido
curl -X POST 'https://<endereço-da-API>/api/clientes/<id>/movimentos' \
-H 'X-Api-Key: <a-sua-chave>' \
-H 'Idempotency-Key: <um-GUID-novo>' \
-H 'Content-Type: application/json' \
-d '{
"data": "2026-10-12T09:00:00Z",
"valor": 0,
"tipo": "Debito"
}'