ContasPagar
CRUD de Título a Pagar (tabela SE2) via rotina automática
FINA050 (MsExecAuto). Cobre títulos comuns
(NF, PRV, CHQ) e adiantamentos (PA) — o que muda é o
tipo do payload. O identificador externo é a
chave composta natural da SE2 com 7 partes:
filial-prefixo-num-parcela-tipo-fornece-loja.
No POST sem {key} o servidor gera
E2_NUM via GetSXENum (avança SX8 em caso
de gap). Esta revisão adiciona validação de domínio
(fValDom) sobre E2_FLUXO antes do
FINA050.
Endpoint OAuth2
Sem credenciais? Você pode pegar o token rodando
./src/scripts/get-token.sh na biblioteca e
colar o access_token aqui no campo de refresh
(ou clique em "Logout" para limpar e voltar ao fake).
Vinculação com o ERP
Convenções
Identificador externo — chave composta. A chave é um único
parâmetro {key} com 7 partes separadas por hífen:
filial-prefixo-num-parcela-tipo-fornece-loja. Exemplo:
01-TST-000123-001-NF-000001-01. Quando o body do
POST/PUT traz os mesmos campos, o path
sempre vence. Pattern: ^[^-]+-[^-]+-[^-]+-[^-]+-[^-]+-[^-]+-[^-]+$.
Título normal × Adiantamento (PA). O endpoint serve os
dois cenários — o que muda é o tipo. NF,
PRV, CHQ, BOL representam títulos
comuns; PA indica adiantamento a fornecedor (sem nota
fiscal). Em PA o E2_NATUREZ tipicamente
referencia uma natureza de adiantamento, e o título já nasce com
E2_SALDO = E2_VALOR aguardando baixa contra a nota futura.
Whitelist por operação. POST aceita os 17 campos do
cadastro completo (TituloPayload); PUT aceita apenas
4 campos editáveis: E2_NATUREZ,
E2_VENCREA, E2_VALOR, E2_HIST
(TituloPayloadPut). Campo fora do whitelist no PUT é
silenciosamente ignorado — FINA050 não toca o registro. Para
mudar valor de campo travado é preciso DELETE + POST de uma nova
parcela.
Validação de domínio no POST/PUT. E2_FLUXO
aceita apenas "S" ou "N" (Pertence "SN" do SX3).
Static fValDom rejeita valores fora do domínio com
422 antes do FINA050, devolvendo mensagem
clara em vez do HELP opaco da rotina:
"E2_FLUXO invalido: 'X'. Aceitos: S (Sim, gera fluxo de caixa), N (Nao).".
Campo não informado / vazio é aceito (default do dicionário).
E2_FILIAL nunca vai no array do MsExecAuto em UPDATE/DELETE.
O caller posiciona SE2 antes da chamada e FINA050
usa xFilial("SE2") internamente. Passar E2_FILIAL em
nOper=4 ou nOper=5 reentra em FA050INCLU e
dispara o erro "Numero titulo ja existe" (FA050NUM) de
forma espúria. Esta restrição vem da build atual (240223P/PRX 04/09/2025).
Soft-delete & unique index. A exclusão via
FINA050 modo 5 marca o registro com D_E_L_E_T_='*'
(soft-delete TOTVS) — o slot do índice único SE2990_UNQ
continua ocupado. Logo, recriar título com chave idêntica
(mesma filial/prefixo/num/parcela/tipo/fornece/loja) falha com 422
até purge físico. Em smoke tests, use num diferente ou
parcela diferente entre execuções.
Formato de datas. Campos E2_EMISSAO,
E2_VENCTO, E2_VENCREA aceitam string
YYYYMMDD (8 dígitos, sem separadores) no payload. A
conversão interna usa SToD(AllTrim(valor)). Em qualquer GET,
datas voltam serializadas pelo U_RestMontaRegistro.
Paginação e delta-sync. /_list usa
page/pageSize (default 50, máx
500) com orderBy=chave. Para sincronização
incremental, alterne para orderBy=recno e use
cursor conforme o nextCursor retornado. Em
orderBy=chave, since filtra
RecNo() < since.
ContasPagar
CRUD por chave composta — título normal e adiantamento (PA)num via GetSXENum)
Descrição
Inclui um título a pagar via FINA050 em modo 3
(MODEL_OPERATION_INSERT). O servidor gera E2_NUM
via GetSXENum + Soma1 em loop até encontrar gap
livre na chave. Retorna a chave técnica completa em data,
com auto: true.
- Para título comum (NF/PRV/CHQ), informe o
tipousual da parametrização. - Para adiantamento (sem nota), use
tipo: "PA"— mesmo endpoint, mesmo payload. E2_FLUXOvalidado contra o domínio do SX3 (Pertence "SN") antes do FINA050.- Whitelist completa: ver
TituloPayload.
Request body
num) + campos do whitelist.
Schema completo em TituloPayload.
POST https://erpapi.jetme.com.br/api/99/01/WsContasPagar/INCLUIR Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Content-Type: application/json Accept: application/json { "filial": "01", "prefixo": "TST", "parcela": "001", "tipo": "NF", "fornece": "000002", "loja": "01", "E2_NATUREZ": "201", "E2_EMISSAO": "20991231", "E2_VENCTO": "20991231", "E2_VALOR": 99.99, "E2_HIST": "TESTE_REST CONTAS A PAGAR" }
POST https://erpapi.jetme.com.br/api/99/01/WsContasPagar/INCLUIR Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Content-Type: application/json Accept: application/json { "filial": "01", "prefixo": "TST", "parcela": "001", "tipo": "NF", "fornece": "000002", "loja": "01", "E2_NATUREZ": "201", "E2_EMISSAO": "20991231", "E2_VENCTO": "20991231", "E2_VALOR": 99.99, "E2_HIST": "TESTE_REST FLUXO S", "E2_FLUXO": "S" }
POST https://erpapi.jetme.com.br/api/99/01/WsContasPagar/INCLUIR Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Content-Type: application/json Accept: application/json { "filial": "01", "prefixo": "TST", "parcela": "001", "tipo": "NF", "fornece": "000002", "loja": "01", "E2_NATUREZ": "201", "E2_EMISSAO": "20991231", "E2_VENCTO": "20991231", "E2_VALOR": 99.99, "E2_HIST": "TESTE_REST FLUXO INVALIDO", "E2_FLUXO": "X" }
{
"success": false,
"message": "E2_FLUXO invalido: 'X'. Aceitos: S (Sim, gera fluxo de caixa), N (Nao).",
"data": ""
}
POST https://erpapi.jetme.com.br/api/99/01/WsContasPagar/INCLUIR Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Content-Type: application/json Accept: application/json { "filial": "01", "prefixo": "TST", "parcela": "001", "tipo": "NF", "fornece": "000002", "loja": "01", "E2_EMISSAO": "20991231", "E2_VENCTO": "20991231", "E2_VALOR": 99.99 }
Respostas
CrudResponse com data = TituloRef (chave de negócio resolvida + auto: true + ids técnicos).filial, prefixo, parcela, tipo, fornece, loja). Tier: validation-error.SE2990_UNQ. Tier: business-error.fValDom) ou rejeição do FINA050 — E2_FLUXO fora de "SN", fornecedor inexistente/bloqueado, natureza inválida, valor zerado, vencimento < emissão, etc. Mensagem editorial em message. Tier: business-error.num forçado pelo cliente
Descrição
Variante do POST em que o cliente impõe a chave completa
via path (incluindo num). Útil para integrações que precisam
preservar o número de origem (NF do fornecedor, número externo do sistema
consumidor). Se a chave já existir, retorna 409 sem tocar
no registro existente.
O path sempre vence sobre o body. Os 7 segmentos do path substituem os campos correspondentes do payload — o body só precisa carregar os campos não-chave (valor, vencimento, natureza, histórico).
Path parameter
filial-prefixo-num-parcela-tipo-fornece-loja. Pattern: ^[^-]+-[^-]+-[^-]+-[^-]+-[^-]+-[^-]+-[^-]+$.Request body
TituloPayload.
POST https://erpapi.jetme.com.br/api/99/01/WsContasPagar/INCLUIR/01-TST-999998-001-NF-000002-01 Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Content-Type: application/json Accept: application/json { "E2_NATUREZ": "201", "E2_EMISSAO": "20991231", "E2_VENCTO": "20991231", "E2_VALOR": 250.00, "E2_HIST": "NF EXTERNA 999998" }
Respostas
num forçado. data.auto = false.fValDom (E2_FLUXO fora de "SN") ou rejeição do FINA050 (mesmas causas do POST sem key).Descrição
Altera campos do título via FINA050 em modo 4
(MODEL_OPERATION_UPDATE). Escopo de negócio reduzido:
apenas 4 campos entram no array do MsExecAuto:
E2_NATUREZ— natureza financeiraE2_VENCREA— vencimento realE2_VALOR— valor do títuloE2_HIST— histórico
Campo fora do whitelist é silenciosamente ignorado. Para
alterar campo travado (fornecedor, número, tipo, prefixo, parcela) use
DELETE + POST. E2_FILIAL nunca entra no array em UPDATE — ver
Convenções.
Path parameter
Request body
TituloPayloadPut.
PUT https://erpapi.jetme.com.br/api/99/01/WsContasPagar/ALTERAR/01-TST-000123-001-NF-000002-01 Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Content-Type: application/json Accept: application/json { "E2_VALOR": 199.99, "E2_HIST": "TESTE_REST CONTAS A PAGAR ALTERADO" }
Respostas
CrudResponse.FINA050 — natureza inexistente, valor inválido, regra de negócio violada. Tier: business-error.Descrição
Exclui o título via FINA050 em modo 5
(MODEL_OPERATION_DELETE). Pré-requisitos:
- Título sem baixa parcial (
E2_SALDO == E2_VALOR). - Sem movimentação contábil/bancária pendente.
- Fornecedor não bloqueado.
Soft-delete TOTVS: marca D_E_L_E_T_='*', mantendo
o slot do unique index ocupado. Reincluir título com chave idêntica falha até
purge físico (ver Convenções).
Path parameter
Cenario
Exemplo da requisicao (cenario ativo)
DELETE https://erpapi.jetme.com.br/api/99/01/WsContasPagar/EXCLUIR/01-TST-000123-001-NF-000002-01 Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Accept: application/json
Respostas
Descrição
Retorna o cabeçalho do título posicionado pela chave composta (índice 1
da SE2: E2_FILIAL+E2_PREFIXO+E2_NUM+E2_PARCELA+E2_TIPO+E2_FORNECE+E2_LOJA).
Cada parte é preenchida com PadR no TamSX3 correspondente
antes do DbSeek. Aplica whitelist de CAMPOS_GET
(cabeçalho da SE2, sem o detalhe de movimento da SE5).
Path parameter
Cenario
Exemplo da requisicao (cenario ativo)
GET https://erpapi.jetme.com.br/api/99/01/WsContasPagar/01-TST-000123-001-NF-000002-01 Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Accept: application/json
Respostas
{ success: true, data: Titulo }.Descrição
Busca o título por id técnico — útil para integrações que persistem
recno ou msuid e querem reconfirmar o registro
sem decompor a chave de negócio em 7 partes.
Query parameters
recnomsuidtipo=recno, string para tipo=msuid.Cenarios
Exemplo da requisicao (cenario ativo)
GET https://erpapi.jetme.com.br/api/99/01/WsContasPagar/_byid?tipo=recno&valor=12345 Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Accept: application/json
GET https://erpapi.jetme.com.br/api/99/01/WsContasPagar/_byid?tipo=msuid&valor=9f7a3e2c4b8d1a0e Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Accept: application/json
Respostas
{ success: true, data: Titulo }.tipo/valor ausentes, tipo fora do enum, valor não numérico para recno.msuid requer campo E2_MSUID no dicionário.Listagem
Paginação por filtros e delta-syncDescrição
Lista títulos com filtros por filial, prefixo,
num, fornece, loja em dois modos:
orderBy=chave(default) — usa o índice 1 da SE2; paginação porpage/pageSize.orderBy=recno— varre fisicamente (ordem 0); paginação por keyset comcursor/nextCursor. Indicado para sync incremental.
Em orderBy=chave, since descarta registros com
RecNo() < since. Em orderBy=recno,
cursor retoma logo após o último RecNo retornado.
Query parameters
xFilial("SE2").CAMPOS_GET.1, mínimo 1). Só faz sentido com orderBy=chave.50, máx 500).chave.chaverecnoorderBy=chave, descarta RecNo() < since.orderBy=recno, retoma após este RecNo (vindo de nextCursor).Cenarios
Exemplo da requisicao (cenario ativo)
GET https://erpapi.jetme.com.br/api/99/01/WsContasPagar/_list?page=1&pageSize=50 Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Accept: application/json
GET https://erpapi.jetme.com.br/api/99/01/WsContasPagar/_list?fornece=000002&loja=01 Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Accept: application/json
GET https://erpapi.jetme.com.br/api/99/01/WsContasPagar/_list?orderBy=recno&cursor=0&pageSize=200 Authorization: Bearer eyJhbGciOiJIUzI1NiIs… Accept: application/json
Respostas
data (array de Titulo), orderBy, pageSize, count, opcionalmente page ou nextCursor conforme o modo.fields com campo fora do whitelist, pageSize > 500).Schemas
Definições canônicas — campos com origemSX3 rastreável
/{key}, /_list,
/_byid). Cabeçalho da SE2 + ids técnicos.
GetSXENum no POST sem key).NF / PRV / CHQ / BOL / PA ... (parametrização SX5/05).YYYYMMDD).E2_MSUID.POST (whitelist CAMPOS_ALLOW_POST).
Campos-chave (filial, prefixo, num,
parcela, tipo, fornece, loja)
podem vir tanto no path ({key}) quanto no body — path sempre vence.
xFilial("SE2") quando omitido.POST /INCLUIR (servidor gera)."001" para única).NF/PRV/CHQ/BOL/PA...YYYYMMDD.YYYYMMDD.fValDom.SN
* Obrigatoriedade dos campos-chave: no POST /INCLUIR sem
{key}, os 6 campos não-num são obrigatórios no body.
Quando há {key} no path, o body não precisa repeti-los.
PUT (CAMPOS_ALLOW_PUT) — somente
4 campos editáveis. Campo fora desta lista é silenciosamente
ignorado.
YYYYMMDD).E2_SALDO.data nas respostas
de POST e PUT. Acrescenta ids técnicos.
true quando o servidor gerou num (POST sem key); false caso contrário.E2_MSUID.data traz
TituloRef em POST/PUT, string vazia em DELETE.
true em sucesso.message traz a
mensagem do NomeAutoLog do FINA050 (ou a mensagem
editorial de fValDom quando o erro é de domínio).
false em erros.Cenários
Catálogo de combinações de payload/query reconhecidas pelos métodos. Cada cenário usa o mesmo schema mas demonstra um uso típico distinto. Tier semântico no slug; endpoint notype-pill.
num gerado pelo servidor via GetSXENum.
Quando usar: caso de uso padrao do CRUD.
incluir-simples + E2_FLUXO="S"
(gera lancamento no fluxo de caixa). fValDom aceita; FINA050 grava.
Quando usar: titulos que devem refletir em projecao de fluxo de caixa.
num). Util para
preservar numero externo (NF do fornecedor, ID de sistema integrador). Path vence
sobre body.
Quando usar: integracoes que precisam manter o numero de origem.
E2_FLUXO fora do
Pertence("SN"). Static fValDom rejeita antes do FINA050,
devolvendo mensagem clara em vez do HELP opaco. Valores aceitos:
S (Sim, gera fluxo de caixa), N (Nao).
SE2990_UNQ. Por causa do soft-delete TOTVS, o slot do indice
fica ocupado mesmo apos DELETE -- recriar com chave identica falha ate purge
fisico. Use num ou parcela distintos.
E2_NATUREZ,
E2_VENCREA, E2_VALOR, E2_HIST) via
FINA050 Op=4. Campos fora do whitelist sao silenciosamente ignorados.
Quando usar: reagendar vencimento, ajustar valor, trocar natureza ou historico.
FINA050 Op=5. Soft-delete TOTVS
(D_E_L_E_T_='*') -- slot do unique index continua ocupado.
Bloqueio: 422 quando ha saldo parcial, movimentacao pendente ou fornecedor bloqueado.
DbSeek pelo indice 1 da SE2 (chave composta com PadR). Retorna
envelope { success, data: Titulo }.
RecNo() via tipo=recno&valor=N. Identificador
tecnico sempre disponivel.
E2_MSUID via tipo=msuid&valor=GUID. Requer
o campo no dicionario (UPDDISTR de MVC). Sem o campo -> 501.
orderBy=chave + page/pageSize.
Paginacao por offset sobre o indice 1 da SE2.
fornece + loja percorrem o indice ate o
fornecedor mudar. num, prefixo, filial
tambem combinaveis.
orderBy=recno + cursor retomavel. Cada pagina devolve
nextCursor para a proxima chamada. since (RecNo<valor)
tambem aceito como filtro de corte.
Quando usar: sincronizacao incremental do consumer (Angular embarcado, integradores externos).
Pendências conhecidas (rev3)
Cenários FINA050 não cobertos. O CRUD básico
desta revisão expõe apenas título "puro". Cenários avançados que
o FINA050 suporta mas que ainda não estão no payload:
complementoTitulo/complementoImpostos (FKF/FKG —
INSS, IR retido, dispensa por processo), rateioContabil
(CTJ, LP 511), rateioProjeto (PMS · AFR/AF9/AF8),
substituição de título provisório (Op=6), abatimento (AB-),
valores acessórios (VA), PA com cheque. Backlog consolidado em
.meta/wip/FEAT-WsSE2-complementos-fina050.md; cada
subtask abre slot próprio sob demanda.
Risco conhecido em E2_CODRET. O
campo está na whitelist do POST mas o wrapper ainda não
chama SetFunName("FINA050") antes do MsExecAuto,
o que pode quebrar o X3_VALID quando o cliente enviar
E2_CODRET. Tracking na subtask 7.8 da FEAT acima. Workaround:
omitir o campo do payload.
PUT restrito a 4 campos de negócio. Por desenho,
o PUT aceita apenas E2_NATUREZ,
E2_VENCREA, E2_VALOR e E2_HIST —
qualquer outro campo no body é silenciosamente ignorado pelo
MsExecAuto (TOTVS). Para alterar fornecedor, prefixo ou
número, faça DELETE + POST. Não é bug,
é a fronteira do que o FINA050 Op=4 considera mutável.
Bloqueio MSBLQL/MSBLQD ainda não aplicado. O
padrão da biblioteca (validado em SA1/SA2/SB1/SB5/SC1) ainda não
chegou ao WsSE2. Hoje o PUT em título não-bloqueado
opera normal; quando entrar a onda em SE2, vai ser preciso aceitar
PUT apenas em E2_MSBLQL/E2_MSBLQD enquanto
o título estiver bloqueado.
Soft-delete TOTVS e índice SE2990_UNQ.
O DELETE faz soft-delete (D_E_L_E_T_='*'),
mas o slot do índice único permanece ocupado no MSSQL — recriar o
mesmo título logo após um DELETE pode retornar
409 mesmo o registro não estando mais visível via
GET. Para reaproveitar a chave, fazer DELETE
físico via DBA ou usar nova chave.