\n"); } function chamar(string $metodo, string $caminho, ?array $corpo, string $apiKey, string $idempotencyKey = ''): array { $tentativas = 0; do { $tentativas++; $correlationId = bin2hex(random_bytes(16)); $headers = [ 'Accept: application/json', 'Authorization: Bearer ' . $apiKey, 'X-Correlation-Id: ' . $correlationId, ]; if ($corpo !== null) $headers[] = 'Content-Type: application/json'; if ($idempotencyKey !== '') $headers[] = 'Idempotency-Key: ' . $idempotencyKey; $ch = curl_init(BASE_URL . $caminho); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => $metodo, CURLOPT_HTTPHEADER => $headers, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_TIMEOUT => 30, ]); if ($corpo !== null) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($corpo, JSON_UNESCAPED_UNICODE)); } $resposta = curl_exec($ch); $status = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE); curl_close($ch); // Repetir somente falha de rede, 429 ou 5xx — MESMA Idempotency-Key. $repetir = ($status === 0 || $status === 429 || $status >= 500) && $tentativas <= 3; if ($repetir) { $espera = 2 ** ($tentativas - 1); // 1s, 2s, 4s fwrite(STDERR, "HTTP $status — repetindo em {$espera}s...\n"); sleep($espera); } } while ($repetir); return [$status, json_decode((string) $resposta, true)]; } // 1) Health-check [$status] = chamar('GET', '/health', null, $apiKey); echo $status === 200 ? "Health-check: OK\n" : exit("API indisponível (HTTP $status)\n"); // 2) Analisar operação (caso clássico: CEST com tributação comum) $idempotencyKey = 'pedido-' . bin2hex(random_bytes(8)); // no ERP: ID do teu registro [$status, $json] = chamar('POST', '/analyses/operation', [ 'company_id' => $empresaId, 'origin_uf' => 'RS', 'destination_uf' => 'SC', 'ncm' => '22021000', 'cest' => '0301100', 'cfop' => '6102', 'csosn' => '102', 'value' => 1500.00, 'product_description' => 'Refrigerante Cola 2 L (exemplo PHP)', ], $apiKey, $idempotencyKey); if ($status !== 200 && $status !== 201) { exit('Erro HTTP ' . $status . ': ' . ($json['error']['message'] ?? json_encode($json)) . "\n"); } $dados = $json['data']; printf("Análise %s | risco=%s | pontuação=%d | motor=%s\n", $dados['reference'], $dados['risk_level'], $dados['score'], $dados['engine_version']); $bloquear = false; foreach ($dados['findings'] as $achado) { printf(" [%s %s] %s (confiança %d%%)\n Sugestão: %s\n", $achado['severity'], $achado['rule_code'], $achado['title'], $achado['confidence'], $achado['suggestion']); if (in_array($achado['severity'], ['high', 'critical'], true)) $bloquear = true; } echo $bloquear ? "VEREDITO: NÃO emitir — corrigir os achados primeiro.\n" : "VEREDITO: liberado para emitir.\n";