Receber Nota Fiscal
Descrição: Recebe o XML de uma Nota Fiscal eletrônica (NF-e) e vincula-a a uma negociação existente. A finalidade da NF é classificada automaticamente pela Matriz CFOP a partir do conteúdo do XML e — quando aplicável — alimenta o saldo de caixa logística da negociação.
O endpoint é o ponto de entrada para integradores externos (ERPs, sistemas cooperativos) registrarem NFs eletrônicas no fluxo da Merx. Toda a lógica de parse do XML, classificação CFOP, validações cross-field e impacto em saldo é executada de forma síncrona — a resposta 200 OK confirma o aceite da NF.
Endpoint
Exemplo de Requisição
curl -X POST \
-H "Authorization: [[apiKey]]" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
"https://api.merx.tech/api/v1/integration/invoices" \
--data '{
"commitment_id": "17b75d09-bcca-43d1-a656-cb6226b74a83",
"xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><nfeProc>...</nfeProc>",
"external_id": "ERP-NF-000122",
"silo_id": "e168db8c-4fa2-4728-9ec3-945207fa474c"
}'
Parâmetros
Parâmetros de Cabeçalho
| Nome | Descrição | Tipo | Obrigatório |
|---|---|---|---|
| Authorization | Token de autenticação | String | Sim |
| Content-Type | application/json | String | Sim |
Parâmetros do Corpo
| Nome | Descrição | Tipo | Obrigatório | Validações |
|---|---|---|---|---|
| commitment_id | Identificador da negociação na plataforma Merx | UUID | Sim | - |
| xml | Conteúdo do XML da NF-e (string) | String | Sim | Não pode ser vazio |
| external_id | Identificador externo do integrador. Usado para deduplicação — duas NFs com o mesmo external_id por cooperativa serão rejeitadas | String | Não | - |
| silo_id | Silo de destino quando a nota movimenta saldo de caixa logística | UUID | Não | Quando informado, deve pertencer à unidade logística da negociação |
| id_report_esg | ID de um relatório ESG pré-gerado para reaproveitar na rastreabilidade automática | UUID | Não | Quando informado, id_report_eudr também deve ser informado |
| id_report_eudr | ID de um relatório EUDR pré-gerado para reaproveitar na rastreabilidade automática | UUID | Não | Quando informado, id_report_esg também deve ser informado |
Importante: a finalidade da NF é classificada automaticamente pela Matriz CFOP a partir do CFOP extraído do XML (e do
finNFe, quando aplicável). O integrador não declara a finalidade — basta enviar o XML e o sistema resolve a classificação durante a validação.
Finalidades classificadas pela Matriz CFOP
Cada finalidade cobre um conjunto de CFOPs e tem um impacto específico no saldo da caixa logística da negociação. Esta tabela é informativa — a classificação é feita automaticamente pelo backend.
| Finalidade | CFOPs típicos | Impacto na caixa | Descrição |
|---|---|---|---|
| VENDA_PRODUTOR | 5101/5102, 6101/6102, 5401/6401 | SOMA | NF de venda emitida pelo produtor |
| CONTRANOTA | 1101/1102, 2101/2102, 1401/2401, 1403/2403 | SOMA | NF de compra emitida pela cooperativa/cerealista após pesagem |
| COMPLEMENTAR | 1949/2949, 1101/2101, 1102/2102 (com finNFe=2) | SOMA* | Ajuste de valor/preço da NF original |
| DEVOLUCAO | 5201/5202/5411, 6201/6202/6411 | SUBTRAI | Devolução de mercadoria não conforme |
| DEVOLUCAO_SIMBOLICA_ARMAZENAGEM | 1906/2906 | SUBTRAI | Reversão simbólica antes da contranota |
| REMESSA_ARMAZENAGEM | 5905/6905 | SOMA | Remessa real para armazém-geral |
| RETORNO_ARMAZENAGEM | 1906/2906 | SOMA | Espelho da REMESSA_ARMAZENAGEM no retorno |
| TRANSFERENCIA | 1151/1152/1154, 2151/2152/2154 | SOMA | Movimentação entre filiais da mesma empresa |
| REMESSA_SIMBOLICA | 5907/6907 | NEUTRO | Venda quando a mercadoria já está no armazém do comprador |
| RETORNO_SIMBOLICO | 1907/2907 | NEUTRO | Espelho de REMESSA_SIMBOLICA |
| REMESSA_INDUSTRIALIZACAO | 5901/6901 | NEUTRO | Esmagamento por encomenda — saída sem titularidade |
| RETORNO_INDUSTRIALIZACAO | 1902/2902 | SOMA | Farelo/óleo retornando após esmagamento |
CFOPs fora do escopo V1:
- 3xxx (importação) —
3101,3102são rejeitados commessage.invoice.cfop.import-not-supported- 7xxx (exportação direta) —
7101,7102são rejeitados commessage.invoice.cfop.export-not-supported- CFOPs não presentes na Matriz são rejeitados com
message.invoice.cfop.not-mapped
Respostas
- 200 - Ok
{
"nf_import_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
| Nome | Descrição | Tipo |
|---|---|---|
| nf_import_id | Identificador único da NF importada na plataforma Merx | UUID |
- 400 - Bad Request
{
"messages": [
"message.invoice.commitment-id.mandatory"
]
}
As mensagens retornadas pelo backend são chaves de internacionalização (i18n) — o cliente deve resolvê-las para a string final exibida ao usuário. A interpolação de valores dinâmicos (CFOP, finalidade etc.) é feita no log do servidor e na resolução i18n no cliente, não no body da resposta.
Validações de campos do request (camada de gateway):
| Cenário | Mensagem retornada |
|---|---|
commitment_id ausente | message.invoice-import.commitment-id.mandatory |
xml ausente ou vazio | message.invoice-import.xml.mandatory |
Validações de negociação:
| Cenário | Mensagem retornada |
|---|---|
commitment_id informado não existe | message.invoice.commitment.not-found |
commitment_id não pertence à cooperativa do token | message.invoice.commitment.not-belongs-to-cooperative |
Negociação não está em status OPEN | message.invoice.commitment.not-open |
| Cooperativa não tem o configurador de NF cadastrado | message.invoice.settings.not-configured |
Validações de duplicidade:
| Cenário | Mensagem retornada |
|---|---|
NF duplicada (mesmo external_id para a mesma cooperativa) | message.invoice.duplicate.external-id |
NF duplicada (mesmo XML — xml_hash) para a mesma negociação | message.invoice.duplicate.xml-hash |
| Race condition de persistência (constraint única violada em concorrência) | message.invoice.duplicate.persistence |
Para BOTH: negociação já tem VENDA_PRODUTOR e veio CONTRANOTA | message.invoice.both.commitment-has-producer-note |
Para BOTH: negociação já tem CONTRANOTA e veio VENDA_PRODUTOR | message.invoice.both.commitment-has-counter-note |
COMPLEMENTAR recebida sem NF de entrada prévia para a negociação | message.invoice.complement.no-prior-entry-for-both |
Exclusividade do configurador de NF: os modos PRODUCER_NOTE ("Nota do Produtor") e COUNTER_NOTE ("Contranota") são mutuamente exclusivos. Uma cooperativa em modo puro só aceita CFOPs da família correspondente — CFOPs da família oposta são rejeitados antes de qualquer impacto na caixa logística.
| Cenário | Mensagem retornada |
|---|---|
Cooperativa em PRODUCER_NOTE recebeu NF classificada como CONTRANOTA (CFOP 1101/1102/1401/1403/2101/2102/2401/2403) | message.invoice.contranota.not-allowed-for-producer-note |
Cooperativa em COUNTER_NOTE recebeu NF classificada como VENDA_PRODUTOR (CFOP 5101/5102/5401/6101/6102/6401) | message.invoice.venda-produtor.not-allowed-for-counter-note |
Validações de XML / parse:
| Cenário | Mensagem retornada |
|---|---|
| XML mal formado / não parseável | message.invoice.xml.parse-error |
Tag obrigatória ausente no XML (ex.: det/prod/CFOP) | message.invoice.xml.missing-required-tag |
Quantidade (qCom) ausente ou não numérica | message.invoice.xml.volume.invalid |
Unidade de medida (uCom) não suportada (≠ KG/TON/SC) | message.invoice.xml.unit-not-supported |
Validações de Matriz CFOP / finalidade:
| Cenário | Mensagem retornada |
|---|---|
finNFe=AJUSTE (ajuste fiscal) — não suportado no V1 | message.invoice.finnfe.ajuste-not-supported |
finNFe=DEVOLUCAO ou finNFe=COMPLEMENTAR incompatível com o CFOP do item | message.invoice.finnfe.incompatible-with-cfop |
| CFOP ausente no XML | message.invoice.cfop.not-found |
| CFOP 3xxx (importação direta) — fora do escopo V1 | message.invoice.cfop.import-not-supported |
| CFOP 7xxx (exportação direta) — fora do escopo V1 | message.invoice.cfop.export-not-supported |
| CFOP não cadastrado na Matriz CFOP | message.invoice.cfop.not-mapped |
| CFOP mapeia múltiplas finalidades sem regra de desambiguação | message.invoice.cfop.ambiguous-purposes |
Validações específicas de DEVOLUCAO (finalidade 4): NFs de devolução só podem subtrair volume que já foi entregue à negociação (ou ao silo informado).
| Cenário | Mensagem retornada |
|---|---|
DEVOLUCAO recebida em negociação sem volume entregue (ou silo sem volume entregue) | message.invoice.devolucao.no-delivered-volume |
DEVOLUCAO cujo volume excede o volume entregue à negociação (ou ao silo informado) | message.invoice.devolucao.exceeds-delivered-volume |
Validações de partes (CNPJ/CPF/IE):
| Cenário | Mensagem retornada |
|---|---|
Emitente do XML não bate com o produtor (VENDA_PRODUTOR) ou a cooperativa (CONTRANOTA) | message.invoice.party.emit-document-mismatch |
Destinatário do XML não bate com a cooperativa (VENDA_PRODUTOR) ou o produtor (CONTRANOTA) | message.invoice.party.dest-document-mismatch |
| Rastreabilidade automática habilitada e IE ausente no XML | message.invoice.ie.mandatory-when-automatic-traceability |
| Rastreabilidade automática habilitada e IE do XML não encontrada nas fazendas do produtor | message.invoice.ie.not-found-in-farms |
Validações de caixa logística / silo:
| Cenário | Mensagem retornada |
|---|---|
| Volume da NF excede a capacidade atual da caixa logística | message.invoice.logistics-box.capacity-exceeded |
silo_id não pertence à unidade logística da negociação | message.invoice.silo.not-belongs-to-logistics-box |
| Volume da NF excede a capacidade atual do silo informado | message.invoice.silo.capacity-exceeded |
Validações de relatórios pré-gerados (id_report_esg / id_report_eudr):
| Cenário | Mensagem retornada |
|---|---|
Apenas um entre id_report_esg e id_report_eudr informado (validação de payload) | message.invoice-import.reports.must-provide-both-or-neither |
Apenas um entre id_report_esg e id_report_eudr informado (validação de domínio) | message.invoice.report.both-required |
id_report_esg informado mas relatório ESG não encontrado no Carbon | message.invoice.report.esg.not-found |
id_report_eudr informado mas relatório EUDR não encontrado no Carbon | message.invoice.report.eudr.not-found |
| Relatório ESG não corresponde ao CAR da fazenda resolvida pela IE | message.invoice.report.esg.car-mismatch |
| Relatório EUDR não corresponde ao CAR da fazenda resolvida pela IE | message.invoice.report.eudr.car-mismatch |
- 401 - Unauthorized
Token ausente ou inválido.
- 404 - Not Found
{
"messages": [
"message.invoice.commitment.not-found"
]
}
Negociação informada em commitment_id não encontrada.
- 500 - Internal Server Error
Erro interno na comunicação com os serviços de domínio.
Observações
- O endpoint é síncrono: a resposta
200 OKindica que a NF foi recebida, classificada, validada e (quando aplicável) já refletiu impacto em saldo. Não há fluxo de aceite posterior nem polling. - Os campos
id_report_esgeid_report_eudrsão utilizados em conjunto com o fluxo de rastreabilidade automática para reaproveitar relatórios socioambientais e EUDR já gerados anteriormente, evitando reprocessamento. Quando um deles é informado, o outro também precisa ser. Consulte o endpoint de Criar Rastreabilidade para detalhes do fluxo com relatórios pré-gerados. - Cada NF aceita gera um registro com status inicial
RECEIVED. Onf_import_idretornado pode ser utilizado para correlacionar a NF nos webhooks e relatórios subsequentes.