Important
Esta documentação é não oficial. Foi montada a partir de testes práticos e da análise da implementação do adapter no Senior Middleware / Bridge G5.
No Gestão Empresarial | ERP, o JSON Facade Adapter foi disponibilizado a partir da versão 5.10.4.120, de 17/07/2026, a mesma versão usada como base aqui. O comportamento pode variar em outras versões.
Referência: Notas da versão 5.10.4.120 - Senior
O JSON Facade Adapter permite executar serviços G5/Senior usando HTTP com corpo JSON, sem precisar montar manualmente uma requisição SOAP.
Important
O adapter atende corretamente parâmetros de entrada escalares. Estruturas aninhadas não são preservadas, e parâmetros do tipo Set podem ser omitidos silenciosamente da requisição, inclusive com a resposta indicando sucesso.
A saída não tem essa restrição. Respostas com estrutura profunda são convertidas corretamente.
Endpoint:
POST http://SEU_HOST/g5-senior-services/api/v1/jsonfacadeadapter
Headers:
Content-Type: application/json
Accept: application/json
Authorization: Basic ...{
"module": "sapiens",
"service": "com.exemplo",
"port": "Operacao",
"execMode": "sync",
"parameters": {
"Parametro": "valor"
}
}| Campo | Obrigatório | Descrição |
|---|---|---|
module |
Sim | Módulo Senior, por exemplo sapiens. |
service |
Sim | Serviço G5. Aceita o nome puro ou o formato servico@operacao. |
port |
Condicional | Operação do serviço. Dispensável quando a operação já vem embutida em service. Se ambos forem informados, port prevalece. |
execMode |
Não | Modo de execução. Quando omitido, assume sync. |
parameters |
Sim | Parâmetros de entrada do serviço. Aceita objeto vazio ({}). |
Warning
A validação atua sobre o valor dos campos acima, não sobre a presença de campos extras.
Um valor inválido é reclamado. "execMode": "asyncc" retorna BAD_REQUEST com a causa descrita na mensagem.
Já um nome de campo grafado errado não é reclamado, porque propriedades desconhecidas na raiz do JSON são descartadas em silêncio. Confirmado em teste, "exceMode": "async" executa em modo sync, já que o execMode correto ficou ausente e assumiu o padrão.
Confira a grafia dos nomes dos cinco campos, e não apenas os valores. Um erro ali não gera erro nenhum, só comportamento diferente do esperado.
A operação pode ser informada de duas maneiras, e as duas funcionam.
Embutida em service, no formato servico@operacao. O adapter separa as partes e preenche port internamente:
{
"module": "sapiens",
"service": "com.exemplo@FazConta",
"execMode": "sync",
"parameters": {
"Number": 10
}
}Ou separada, com service sem o @ e a operação em port:
{
"module": "sapiens",
"service": "com.exemplo",
"port": "FazConta",
"execMode": "sync",
"parameters": {
"Number": 10
}
}Informar as duas coisas ao mesmo tempo, com service usando @ e port repetindo a mesma operação, também funciona.
Se os dois indicarem operações diferentes, prevalece o que estiver em port.
Confirmado em teste, com FazConta3 e FazConta sendo operações distintas, a requisição abaixo executou o FazConta, indicado em port, e ignorou o FazConta3 embutido em service:
{
"module": "sapiens",
"service": "com.exemplo@FazConta3",
"port": "FazConta",
"execMode": "sync",
"parameters": {
"Number": 10
}
}O motivo é a ordem em que os campos são aplicados, com a operação vinda do @ gravada primeiro e depois sobrescrita por port. É também o que faz a forma separada (service sem @ mais port) funcionar.
Warning
Ainda que o comportamento seja previsível, evite informar operações diferentes nos dois campos. A requisição fica ambígua para quem lê e um erro de digitação no @ passa despercebido, já que o port corrige silenciosamente.
Pode ser omitido. A requisição abaixo, sem execMode, executou normalmente em modo síncrono:
{
"module": "sapiens",
"service": "com.exemplo",
"port": "FazConta",
"parameters": {
"Number": 10
}
}Omitir o campo é diferente de enviá-lo com valor inválido. Um valor fora da lista aceita retorna erro de validação, descrito em Erros HTTP.
O adapter lê o header HTTP Authorization. Na implementação analisada existem quatro esquemas:
Authorization: Basic BASE64(usuario:senha)
Authorization: Bearer TOKEN
Authorization: Encryption TOKEN
Authorization: Trusted TOKENImportant
Os prefixos são case-sensitive. Use exatamente Basic, Bearer, Encryption e Trusted.
Detalhes observados na implementação:
- No
Basic, o conteúdo é decodificado de Base64 e separado no primeiro:. Portanto a senha pode conter:sem escape. Por exemplo,usuario:minha:senha:123resulta em usuáriousuarioe senhaminha:senha:123. - O usuário não pode ser vazio. A senha não passa por validação equivalente nesse ponto.
- Header ausente, ou com um esquema que não seja um dos quatro acima, não é rejeitado de imediato. O processamento segue com credenciais vazias e a falha ocorre depois.
Para Basic Auth, o curl monta o header automaticamente a partir de:
--user 'SEU_USUARIO:SUA_SENHA'Note
Apenas o Basic foi testado em execução. Nos outros três, o adapter coloca o token no lugar da senha e deixa o usuário vazio.
O Middleware persiste cada requisição na tabela R960PAR. O documento gravado carrega a credencial usada na chamada, como atributos do elemento <request>:
<request id='...' user='USUARIO' password='SENHA' encrypted='0'
service='com.exemplo' port='FazConta'>Esse atributo indica a versão de criptografia aplicada à credencial.
Note
O campo tem dois nomes conforme onde é consultado. Na tabela de parâmetros da documentação da Senior ele é chamado de encryption. No XML <request>, tanto o gravado na R960PAR quanto os exemplos publicados pela Senior, o atributo é encrypted. É o mesmo campo.
Versões documentadas pela Senior:
| Valor | Significado | Disponível para terceiros |
|---|---|---|
0 |
Sem criptografia. Usuário e senha ficam como texto UTF-8 no documento interno da requisição. | Sim |
1 |
Senha cifrada com algoritmo próprio da Senior. | Não, apenas entre sistemas Senior |
2 |
Em vez da senha, um token Senior de autenticação, obtido pelo Logon integrado com criptografia. | Sim |
3 |
Em vez da senha, um token do serviço de usuários G7. | Não, apenas entre sistemas Senior |
Autenticando com Basic, o valor observado foi 0, ou seja, senha em texto aberto.
Warning
Com Basic, a senha do usuário de integração fica legível em texto puro para qualquer pessoa com acesso de leitura à R960PAR.
Leve isso em conta ao escolher qual usuário será usado nas integrações e ao conceder acesso ao banco. Prefira um usuário de serviço com permissões restritas, e não uma conta administrativa ou pessoal. Para não gravar a senha, use o esquema Encryption, descrito abaixo.
O adapter não expõe campo para escolher a versão de criptografia. Ela é definida pelo esquema do header Authorization:
| Header | Versão gerada | Como a credencial é enviada | Liberado para terceiros |
|---|---|---|---|
Basic |
0 |
Usuário e senha, ambos em texto aberto | Sim |
Encryption |
2 |
Usuário vazio, token no lugar da senha | Sim |
Bearer |
3 |
Usuário vazio, token da Plataforma Senior no lugar da senha | Não, apenas entre sistemas Senior |
Trusted |
999 |
Usuário vazio, token no lugar da senha | Não, uso interno para chamadas de métodos agendados |
Para sistemas terceiros, portanto, Encryption é a única alternativa documentada ao texto aberto. O Bearer gera a versão 3, reservada pela Senior à integração entre sistemas próprios, e o Trusted é descrito como mecanismo interno para chamadas de métodos agendados. O valor 999 do Trusted não consta na documentação e foi identificado apenas na implementação analisada.
Referência: Autenticação via Headers em Web Services
O token do Encryption vem do Logon integrado com criptografia, que precisa ser habilitado em Central de Configurações > Opções de Segurança, onde também se define a chave usada para descriptografar. O conteúdo segue o formato abaixo e é gerado pelo aplicativo crypt.jar:
DD/MM/YYYY HH:MM:SS|<nome do usuário>
Note
O Encryption não foi testado em execução neste levantamento.
A Senior alerta que o token tem tempo de expiração e que, nas execuções internas entre sistemas Senior, o mecanismo só funciona em modo síncrono. Nos demais modos a execução falha com "Credenciais inválidas". Para sistemas terceiros, a administração do tempo de expiração é responsabilidade da integração.
Valide esse comportamento antes de usar Encryption com execMode: async.
Referências: Tipos de execução e Logon integrado com criptografia
Serviço usado no teste:
Módulo: sapiens
Serviço: com.exemplo
Operação: FazConta
Entrada: Number
Saída: Resultado
Implementação do serviço:
FazConta.Resultado = FazConta.Number * 4;
{
"module": "sapiens",
"service": "com.exemplo",
"port": "FazConta",
"execMode": "sync",
"parameters": {
"Number": 10
}
}curl --location \
'http://SEU_HOST/g5-senior-services/api/v1/jsonfacadeadapter' \
--user 'SEU_USUARIO:SUA_SENHA' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--data '{
"module": "sapiens",
"service": "com.exemplo",
"port": "FazConta",
"execMode": "sync",
"parameters": {
"Number": 10
}
}'Como o serviço multiplica Number por 4, para Number = 10 o retorno observado foi:
{
"result": {
"resultado": 40,
"erroExecucao": null
}
}O status HTTP informa apenas se a chamada ao adapter foi processada. Tanto o erro do serviço quanto a falha de autenticação vêm no corpo da resposta, em result.erroExecucao.
Warning
Nos testes, o adapter respondeu HTTP 200 mesmo com o serviço em erro. Tratar a integração só pelo status HTTP faz o erro passar despercebido.
Quando não há erro, o campo vem como null, como na resposta de sucesso mostrada acima.
Os cenários abaixo foram provocados no com.exemplo@FazConta.
Erro levantado pela regra, com Mensagem(Erro, "Number não pode ser zero") e "Number": 0:
{
"result": {
"resultado": 0,
"erroExecucao": "Ocorreu um erro ao executar o serviço \" \": Number não pode ser zero"
}
}Erro de execução, trocando a implementação por FazConta.Resultado = 100 / FazConta.Number; e enviando "Number": 0:
{
"result": {
"resultado": 0,
"erroExecucao": "Ocorreu um erro ao executar o serviço \" \": Divisão por zero."
}
}Falha de credencial também chega por aqui, e não como erro HTTP de autorização. Usuário inexistente:
{
"result": {
"resultado": 0,
"erroExecucao": "Ocorreu um erro ao executar o serviço \" \": Credenciais inválidas."
}
}Senha incorreta:
{
"result": {
"resultado": 0,
"erroExecucao": "Ocorreu um erro ao executar o serviço \" \": Credenciais inválidas/desabilitadas/expiradas."
}
}Important
As duas respostas vêm com HTTP 200. Uma integração que trate autenticação apenas pelo status HTTP nunca vai perceber que a credencial está errada. Recebe 200, lê o parâmetro de saída com o valor padrão do tipo e segue como se tivesse dado certo.
Repare que a mensagem é diferente nos dois casos. Usuário inexistente responde Credenciais inválidas., enquanto senha incorreta responde Credenciais inválidas/desabilitadas/expiradas.. Nos testes desta versão, portanto, foi possível distinguir os dois pela mensagem retornada.
Observações dos testes:
erroExecucaoé uma string, não um objeto, e não há código de erro separado. A mensagem do serviço vem concatenada ao prefixoOcorreu um erro ao executar o serviço "...":.- O nome do serviço dentro do prefixo não foi preenchido. Em todos os cenários testados ele veio literalmente como
" ", um único espaço entre aspas. Não use esse trecho para identificar a origem do erro. - A mensagem não é construída pelo adapter. O Bridge recebe esse conteúdo da camada de execução e o propaga para
erroExecucao, sem preencher nem corrigir o nome do prefixo. A origem exata do texto não foi localizada na implementação analisada, então não trate esse formato como contrato estável nem faça leitura programática dele. - Os parâmetros de saída retornam o valor padrão do tipo, não
null. No exemplo,resultadoveio0mesmo com o serviço em erro. Ou seja,0não significa sucesso. - Erro levantado pela regra e erro de execução chegam no mesmo formato, ambos com
HTTP 200. Não é possível distinguir a natureza do erro apenas pelo campo.
Por isso, em chamadas síncronas, valide sempre, nesta ordem:
- o status HTTP;
- se o nó
resultexiste, já que em erro do adapter a resposta vem em outro formato, semresult; - se
result.erroExecucaoénull, antes de usar qualquer valor de saída.
Na entrada, a caixa não importa. O nome enviado é comparado ao do contrato do serviço ignorando maiúsculas e minúsculas, então codemp, CODEMP e codEmp casam todos com o mesmo parâmetro.
Confirmado em teste, um serviço que declara Number como parâmetro de entrada respondeu normalmente ao receber NUMBER, com o cálculo correto. Se o nome tivesse sido descartado, o parâmetro de saída teria voltado com o valor padrão do tipo.
O elemento da requisição é reconstruído a partir do nome do contrato, com a normalização de nomes aplicada pelo Bridge, e não necessariamente com a grafia original.
A tolerância é apenas quanto à caixa. Qualquer outro caractere torna o nome diferente, e o parâmetro é descartado em silêncio:
codemp casa com codEmp
CodEmp casa com codEmp
cod.emp não casa
cod_emp não casa
cod-emp não casa
É por isso que as chaves com ponto, como consulta.codSnf, desaparecem sem aviso.
Na saída o comportamento é outro. Nas chaves de resposta, apenas a letra inicial é convertida para minúscula, e o restante do nome é preservado.
Resultado -> resultado
MeuResultadOO -> meuResultadOO
MensagemRetorno -> mensagemRetorno
TipoRetorno -> tipoRetorno
codEmp -> codEmp
camposUsuarioOrcamento -> camposUsuarioOrcamento
Ou seja, um nome que já começa em minúscula chega intacto. Só os que começam com maiúscula mudam, e mudam somente no primeiro caractere.
O par MeuResultadOO veio de um serviço criado especificamente para isolar essa regra. As maiúsculas consecutivas no fim do nome descartam a hipótese de conversão para minúsculo integral, que produziria meuresultadoo.
MensagemRetorno e TipoRetorno confirmam o mesmo em serviço padrão da Senior. Aparecem com essa grafia no registro binário da R960PAR e chegam ao JSON com a inicial minúscula e o resto preservado, mostrando os dois lados da conversão.
Na prática, na entrada não se preocupe com a caixa, apenas com a grafia exata do nome. Na resposta, considere que a inicial pode ter mudado.
Os parâmetros reconhecidos pelo contrato do serviço são reconstruídos como elementos de <params>, dentro do documento <request> que a Senior usa para acionar o serviço.
Este JSON:
{
"parameters": {
"Number": 10
}
}resulta na estrutura abaixo, capturada da requisição efetivamente gravada pelo Middleware:
<request id='...' user='...' password='...' encrypted='0'
service='com.exemplo' port='FazConta'>
<params>
<number>10</number>
</params>
</request>Dois pontos importantes nessa estrutura:
- O elemento é
<params>, dentro de<request>. No envelope SOAP completo existe também um<parameters>em nível externo, que carrega esse documento inteiro. São camadas diferentes. - O nome do parâmetro teve a inicial convertida para minúscula e
Numbervirou<number>. A resolução funcionou mesmo assim. Veja Maiúsculas e minúsculas nos campos.
Por isso, utilize os mesmos nomes definidos nos parâmetros do serviço.
Nos campos numéricos testados, o valor funcionou tanto como número JSON quanto como string. Enviar "codEmp": 1 ou "codEmp": "1" produziu o mesmo resultado.
Para um serviço sem parâmetros de entrada, envie:
{
"parameters": {}
}Caution
O JSON Facade não preserva objetos e listas como estruturas aninhadas. Quando o contrato do serviço espera um parâmetro do tipo Set, o valor acaba omitido da requisição final, mesmo que a chamada responda HTTP 200, com erroExecucao: null e mensagem de sucesso.
Não use este endpoint para serviços cuja entrada exija estrutura aninhada.
Um objeto ou array enviado para um parâmetro declarado como Set não vira estrutura aninhada, e também não chega como texto achatado. Ele é descartado por completo, sem gerar erro.
Nenhuma das quatro formas testadas funcionou, seja objeto aninhado, array, caminho achatado com ponto ou estrutura montada com os nomes exatos do contrato publicado. Para esses parâmetros, use o endpoint SOAP.
O teste usou o serviço padrão com.senior.g5.co.mcm.ven.pedidos, na porta SimularPedidos, que apenas calcula e não grava nada.
Foram feitas quatro chamadas:
- Com um pedido completo, contendo oito produtos, cada um com sua própria lista de campos de usuário.
- Sem o parâmetro
pedido, enviando apenas parâmetros escalares. - Com o pedido completo, porém apontando para um código de cliente inexistente e com o tratamento de erros ligado.
- Com um pedido mínimo, usando exatamente os nomes de campo do contrato publicado do serviço.
As quatro responderam exatamente a mesma coisa:
{
"result": {
"mensagemRetorno": "Processado com sucesso.",
"tipoRetorno": 0,
"erroExecucao": null
}
}Uma simulação de pedido deveria devolver os valores calculados. Não devolveu em nenhuma delas.
A terceira chamada é a decisiva. Com o tratamento de erros ligado e um cliente que não existe, o serviço teria que recusar o pedido. Não recusou porque não recebeu pedido algum. A segunda mostra que a resposta é idêntica com ou sem o parâmetro complexo, ou seja, a mensagem de sucesso não diz nada sobre o conteúdo ter sido processado. E a quarta descarta a hipótese de erro de nomenclatura, já que usou os nomes exatos do contrato.
A requisição gravada confirma o efeito. O elemento de parâmetros veio vazio:
<request id='...' user='...' password='...' encrypted='0'
service='com.senior.g5.co.mcm.ven.pedidos' port='SimularPedidos'><params/></request>Objeto e array se comportam da mesma maneira. A requisição é aceita, executa, e o parâmetro não chega ao serviço.
Valor em parameters |
Comportamento |
|---|---|
Objeto, como "consulta": { ... } |
Aceito. Omitido da requisição final. |
Array, como "consulta": [ { ... } ] |
Aceito. Omitido da requisição final. |
Também não funciona achatar o caminho com ponto, no formato que a própria documentação da Senior usa para nomear os campos de um Set. Enviando "consulta.codSnf" e "consulta.numNfv" junto de três parâmetros escalares, a requisição gravada saiu assim:
<params><codEmp>1</codEmp><codFil>1</codFil><tipExp>N</tipExp></params>Os três escalares passaram. As duas chaves com ponto foram descartadas, e sequer viraram elementos com o nome literal.
O descarte acontece chave por chave, e independe da posição. Repetindo o teste com a chave inválida em primeiro lugar, os escalares seguintes continuaram sendo transmitidos. Uma chave não reconhecida some sozinha, sem afetar as demais e sem gerar aviso.
O mesmo vale para valor objeto e para valor array. Enviando "consulta" das duas formas, ao lado dos três escalares, a requisição gravada saiu idêntica nos dois casos:
<params><codEmp>1</codEmp><codFil>1</codFil><tipExp>N</tipExp></params>Não há elemento <consulta> algum, nem mesmo com o conteúdo achatado em texto. A resposta, nas duas formas, indicou processamento com sucesso.
A conversão acontece em duas etapas, e a estrutura se perde na primeira.
Na etapa inicial, cada valor de parameters é transformado em texto. Um objeto vira algo como {codSnf=01, numNfv=515555} dentro do elemento correspondente.
Na etapa seguinte, o Middleware consulta o contrato do serviço, identifica que aquele parâmetro é do tipo Set e procura elementos XML filhos para remontar a estrutura. Como encontra apenas uma linha de texto, o conjunto resulta vazio e o parâmetro é omitido da requisição final. É por isso que ele não aparece nem achatado no que fica gravado.
Nenhuma variação de formato no JSON contorna isso, porque a estrutura já foi perdida antes de o Middleware tentar interpretá-la. Parâmetros do tipo Set só podem ser enviados pelo endpoint SOAP, onde o XML chega estruturado desde a origem.
O serviço executa com o parâmetro faltando, e nada na resposta indica isso.
No teste de consulta de baixas, o Set descartado era justamente o filtro da busca. A consulta rodou sem filtro algum e respondeu:
{
"result": {
"mensagemRetorno": "Processado com sucesso.",
"tipoRetorno": 1,
"erroExecucao": null
}
}Nenhum título foi retornado, e o tipoRetorno igual a 1 significa "Processado" no contrato do serviço. O campo erros da resposta sequer apareceu. Mesmo com os campos do filtro sendo obrigatórios quando não se informa o número do título, não houve reclamação sobre a ausência deles.
Caution
Uma integração escrita sobre este endpoint recebe HTTP 200, erroExecucao: null e mensagem de sucesso enquanto o parâmetro não chegou e nada foi processado. Uma consulta devolve vazio como se não houvesse registros, e uma operação não acontece como se tivesse acontecido.
Para serviços que exigem estrutura aninhada na entrada, utilize o endpoint SOAP tradicional.
Não existe sinal do descarte na resposta. E no fluxo analisado ele também não gera registro no servidor. O trecho que omite o parâmetro vazio não emite exceção, warning nem debug, e nos testes não apareceu nada correspondente no server.log.
Restam duas formas de perceber o problema, ambas do lado de quem integra:
- Conferir o
<params>da requisição na Consulta de Requisições, comparando com o que foi enviado. É o método confiável, e o único que mostra exatamente o que o serviço recebeu. - Validar o conteúdo da resposta, e não o status nem a mensagem. Numa consulta, tratar retorno vazio como suspeito em vez de conclusivo, já que a ausência de registros e o descarte do filtro produzem exatamente a mesma resposta.
Note
O problema é de entrada. A conversão da resposta funciona corretamente, inclusive com estruturas profundas. Veja Resposta com estrutura complexa.
Serviços padrão da Senior costumam devolver estruturas profundas, com listas dentro de listas. O adapter converte essas estruturas corretamente, gerando objetos e arrays JSON de verdade, sem achatar nada em texto.
O exemplo abaixo usa o serviço padrão com.senior.g5.co.mcm.ven.orcamento, na porta CarregarOrcamentos:
{
"module": "sapiens",
"service": "com.senior.g5.co.mcm.ven.orcamento",
"port": "CarregarOrcamentos",
"execMode": "sync",
"parameters": {
"codEmp": 1,
"numOct": 1,
"verOct": 1
}
}A resposta, com os valores substituídos por dados de exemplo e reduzida para mostrar apenas a estrutura:
{
"result": {
"mensagemRetorno": "Processado com sucesso.",
"tipoRetorno": 0,
"erroExecucao": null,
"orcamento": {
"codEmp": 1,
"numOct": 1,
"vlrLiq": 1000.00,
"datGer": "01/01/2020",
"vldOct": null,
"itens": {
"seqOci": 1,
"codPro": "PRODUTO01",
"desPro": "Produto de exemplo",
"qtdOci": 10.0,
"vlrUni": 100.00
},
"camposUsuarioOrcamento": [
{ "campo": "USU_CAMPO1", "valor": 1 },
{ "campo": "USU_CAMPO2", "valor": 0 },
{ "campo": "USU_CAMPO3", "valor": null }
]
}
}
}Os tipos são preservados. Números chegam como número, null como null, e datas como texto no formato DD/MM/YYYY.
Serviços padrão da Senior costumam trazer também mensagemRetorno e tipoRetorno ao lado do erroExecucao.
Este é o ponto mais importante da conversão, e o mais fácil de não perceber.
No contrato SOAP, itens e camposUsuarioOrcamento são ambos coleções. Na resposta acima:
| Campo | Quantidade de elementos | Tipo no JSON |
|---|---|---|
itens |
1 | objeto |
camposUsuarioOrcamento |
3 | array |
A diferença não está no contrato, e sim na quantidade de registros retornados naquela chamada. Em SOAP, um elemento repetido uma vez e repetido três vezes são a mesma estrutura. Na conversão para JSON deixam de ser.
Isso foi confirmado com o mesmo campo, no mesmo serviço. Consultando um orçamento com um único item, itens veio como objeto. Consultando outro orçamento com vários itens, veio como array. Nada mudou na chamada além do registro consultado.
Warning
Uma integração que percorra orcamento.itens como lista funciona enquanto o orçamento tiver vários itens e quebra quando tiver apenas um. O inverso também vale, e código que trate itens como objeto quebra assim que vier o segundo item.
Antes de percorrer qualquer coleção da resposta, verifique se o valor é array ou objeto e normalize. Não confie no que apareceu no teste, porque a forma depende dos dados daquele registro.
Foram identificados os modos:
sync
async
scheduled
O campo é opcional. Quando omitido, o adapter assume sync, que é o modo em que o cliente aguarda o resultado na própria resposta:
{
"execMode": "sync"
}O Web Service em si possui um quarto modo, o Local, que processa na mesma instância da aplicação, dentro do próprio sistema, sem passar pelo Middleware. Ele não está disponível no adapter. A mensagem de erro de validação cita apenas "Sincrono, Assincrono ou agendado".
Note
A mensagem de erro do adapter cita os modos como "Sincrono, Assincrono ou agendado", mas o valor aceito no JSON é o identificador em minúsculo, como sync e async.
Referências: Tipos de execução e TECNOLOGIA - WebServices - Modos de execução
No modo assíncrono o adapter confirma o recebimento e devolve o controle imediatamente. Não há dados do serviço na resposta:
{
"result": "ok"
}Warning
Repare que result aqui é uma string, e não um objeto. Código que lê result.erroExecucao direto funciona no modo sync e quebra no async.
A resposta não devolve nenhum identificador da requisição. Para acompanhar a execução é preciso consultar a tabela de requisições e localizar o registro por serviço, usuário e horário.
Colunas observadas em uma execução assíncrona bem-sucedida:
| Coluna | Valor observado | Observação |
|---|---|---|
IDREQ |
string opaca de 20 caracteres | Identificador da requisição. Inclui caracteres não alfanuméricos, como [, / e !. Não é devolvido na resposta HTTP. |
TIPSER |
com.exemplo@FazConta |
Gravado sempre no formato servico@operacao, mesmo que a requisição tenha enviado service e port separados. |
STATUS |
4 |
Estado final da requisição. |
PERCON |
100 |
Percentual concluído. |
DATINI / DATFIN |
mesmo horário | A execução foi imediata. |
CODUSU |
código do usuário | Usuário autenticado na chamada. |
O conteúdo da chamada fica na R960PAR, ligada pelo mesmo IDREQ. A coluna TIPPAR separa o que entrou do que saiu:
TIPPAR |
Conteúdo do PARVAL |
|---|---|
0 |
Entrada: o documento <request> completo, incluindo os parâmetros enviados e a credencial usada na chamada. |
1 |
Saída: o retorno do serviço, com os parâmetros de saída. |
O PARVAL é um BLOB, e os dois lados usam formatos diferentes.
A entrada é XML, legível assim que o BLOB é convertido para texto.
A saída não é XML. É um formato binário próprio, em que os nomes dos campos aparecem legíveis em ASCII entre bytes de controle. Em uma consulta de baixa de títulos, por exemplo, aparecem BaixaTitulos, Erros, TipoRetorno e MensagemRetorno, junto do texto da mensagem de retorno.
Note
Recuperar o resultado de uma chamada assíncrona pela tabela exige interpretar esse formato binário. Não basta ler o BLOB como texto.
Repare também que ali os nomes vêm capitalizados, como MensagemRetorno. É a mesma diferença descrita em Maiúsculas e minúsculas nos campos. A resposta JSON entrega mensagemRetorno, com a inicial em minúscula.
Ambas as tabelas são consultáveis pela Consulta de Requisições.
Warning
O valor scheduled é aceito pela validação, mas não é possível criar nem alterar agendamentos por este endpoint. Toda tentativa de criação ou alteração retorna erro interno. A operação de listar os agendamentos existentes, porém, funciona.
No modelo de execução agendada da Senior, a solicitação é armazenada no WildFly para execução posterior pelo Middleware, sem retorno da execução para quem solicitou. Os agendamentos são geridos pelo web service ScheduledService.
O agendamento exige metadados próprios, como operação, periodicidade, intervalo, data e hora iniciais. Eles estão especificados pela Senior em Tipos de execução, e ficam ao lado de parameters, não dentro dele.
A estrutura da requisição JSON não possui campo para nenhum deles. Só existem module, service, port, execMode e parameters.
Foram testadas as duas formas possíveis de tentar enviá-los, usando exatamente os nomes documentados acima, e ambas deram o mesmo resultado:
- Dentro de
parameters. Não funciona, porque tudo que está ali vira parâmetro do serviço dentro de<params>, e não metadado de agendamento. - Na raiz do JSON, ao lado de
moduleeservice. Também não funciona, porque campos desconhecidos são descartados.
Nos dois casos a resposta foi:
{
"message": "Internal server error.",
"path": "/g5-senior-services/api/v1/jsonfacadeadapter",
"internalCode": "INTERNAL_ERROR"
}No server.log, o erro correspondente é um NullPointerException ao ler a operação de agendamento, que permaneceu nula:
java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()"
because the return value of
"br.com.senior.bridge.model.ScheduledModel.getOperation()" is null
Para agendar a execução de um serviço, utilize o endpoint SOAP tradicional, onde os campos de agendamento têm lugar previsto no envelope.
Apesar de não criar agendamentos, o modo scheduled dá acesso a uma operação de consulta. Informando scheduledProcesses em port, o adapter retorna a lista de processos agendados:
{
"module": "sapiens",
"service": "com.exemplo",
"port": "scheduledProcesses",
"execMode": "scheduled",
"parameters": {}
}O service precisa existir, senão a chamada retorna INTERNAL_ERROR como qualquer serviço inválido. Fora isso, a operação não depende dos metadados de agendamento, e é por isso que funciona.
A resposta traz o result como string contendo XML, e não como objeto JSON:
{
"result": "<SERVICE></SERVICE>"
}O exemplo acima é de um ambiente sem agendamentos. O formato do conteúdo com a lista preenchida não foi observado.
Existe também a porta cancel, que remove um agendamento a partir do seu identificador.
Warning
Não utilize cancel por este endpoint. O identificador do agendamento precisaria chegar como metadado, do mesmo modo que os campos de criação, e o contrato JSON não tem onde colocá-lo. A operação é alcançada sem receber o alvo, e o comportamento nesse caso não foi verificado.
| HTTP | internalCode |
Causa | Observado em teste |
|---|---|---|---|
400 |
BAD_REQUEST |
Campo obrigatório ausente ou com valor inválido. Confirmado com execMode fora da lista aceita. |
Sim |
500 |
INTERNAL_ERROR |
Serviço inexistente, erro interno no Bridge ou falha na conversão da requisição/resposta. | Sim |
| varia | nenhum | Rota inexistente ou corpo malformado. Responde em outro formato, sem internalCode. |
Sim |
Important
Credencial inválida não aparece nesta tabela. Nos cenários testados, usuário ou senha errados retornaram HTTP 200, com a falha dentro de result.erroExecucao, e não houve resposta 401.
Esta tabela cobre falhas de transporte e validação, antes ou fora da execução da regra. Erro do próprio serviço não aparece aqui e retorna HTTP 200 com result.erroExecucao preenchido.
Note
Header Authorization malformado, como Base64 inválido no Basic, não foi testado. A leitura da implementação sugere que ele cai no tratamento genérico de erro, e não no de autorização.
Em nenhum teste realizado o adapter respondeu 401.
Quando a falha é do adapter, e não do serviço, a resposta não traz o nó result. O formato é outro, e o campo internalCode identifica a natureza do erro.
Serviço inexistente, usando com.exemploo@FazConta com um o a mais:
{
"message": "Internal server error.",
"path": "/g5-senior-services/api/v1/jsonfacadeadapter",
"timestamp": "2026-08-10T14:50:56.205721500-03:00",
"internalCode": "INTERNAL_ERROR"
}Nome de serviço errado não é tratado como erro de validação da requisição. A validação inicial apenas confere se o campo foi informado, e a falha só acontece depois, ao resolver o serviço.
Campo com valor inválido, usando "execMode": "xyz":
{
"message": "O modo de execução do serviço é inválido. Verifique se está utilizando o modo de execução: Sincrono, Assincrono ou agendado.",
"path": "/g5-senior-services/api/v1/jsonfacadeadapter",
"timestamp": "2026-08-10T15:05:55.987066800-03:00",
"internalCode": "BAD_REQUEST"
}Em BAD_REQUEST o campo message traz a causa real, enquanto em INTERNAL_ERROR vem apenas "Internal server error.", sem detalhe. Para diagnosticar, use o internalCode, não o texto de message.
São sete situações distintas, produzindo quatro estruturas de corpo. A integração precisa lidar com todas:
| Situação | HTTP | Corpo |
|---|---|---|
Serviço executou com sucesso (sync) |
200 |
result como objeto, com erroExecucao: null |
Serviço executou e falhou (sync) |
200 |
result como objeto, com erroExecucao preenchido |
| Credencial inválida | 200 |
result como objeto, com o erro em erroExecucao |
Chamada aceita (async) |
200 |
result como a string "ok", sem dados do serviço |
| Listagem de agendamentos | 200 |
result como string contendo XML, sem conversão para JSON |
| Adapter falhou | 400 ou 500 |
sem result, com message, path, timestamp e internalCode |
| Falha antes do adapter, como rota inexistente ou corpo malformado | erro | sem result, com apenas mensagem e error |
Warning
O nó result muda de tipo conforme o caso. Ler result.erroExecucao diretamente só é válido quando result é um objeto, o que acontece nas três primeiras linhas da tabela. No async e na listagem de agendamentos ele é uma string, e nos erros do adapter o nó nem existe.
Verifique o status HTTP e o tipo de result antes de acessar qualquer campo.
Existe um terceiro envelope de erro, com os campos mensagem e error. Ele não traz result, e também não traz path, timestamp nem internalCode. Aparece quando a falha ocorre antes do adapter processar a requisição.
Rota inexistente, observado ao chamar /api/v1/jsonfacadeadapterr com um r a mais no final:
{
"mensagem": "Consulte os logs para detalhes.",
"error": "Erro na requisição."
}Corpo da requisição malformado:
{
"mensagem": "Verifique se há vírgulas, aspas, chaves ou caracteres inconsistentes na requisição.",
"error": "Erro na estrutura do JSON enviado."
}Esse formato indica falha anterior ao processamento normal da requisição. Nos testes, apareceu com URL inexistente e com corpo malformado, e vale conferir os dois antes de investigar o serviço ou as credenciais.