PHP — Laravel 11
composer require guzzlehttp/guzzleCliente
app/Services/ZfiscooClient.php
<?php
namespace App\Services;
use GuzzleHttp\Client;
use Illuminate\Support\Str;
class ZfiscooClient
{
private Client $http;
public function __construct()
{
$this->http = new Client([
'base_uri' => config('services.zfiscoo.api_url'),
'headers' => [
'Authorization' => 'Bearer ' . config('services.zfiscoo.api_key'),
'Content-Type' => 'application/json',
],
'timeout' => 30.0,
]);
}
public function emitirNfce(string $pedidoId, array $items, array $payment): array
{
$response = $this->http->post('/v1/nfce', [
'headers' => [
'Idempotency-Key' => "nfce:{$pedidoId}",
],
'json' => [
'issuer_id' => config('services.zfiscoo.issuer_id'),
'external_ref' => $pedidoId,
'items' => $items,
'payment' => $payment,
],
]);
return json_decode((string) $response->getBody(), true);
}
}Webhook handler
routes/api.php
use Illuminate\Http\Request;
Route::post('/zfiscoo/webhook', function (Request $request) {
$raw = $request->getContent();
$signature = $request->header('X-Signature', '');
$expected = hash_hmac('sha256', $raw, config('services.zfiscoo.webhook_secret'));
$received = preg_replace('/^sha256=/', '', $signature);
if (! hash_equals($expected, $received)) {
return response()->json(['error' => 'invalid signature'], 401);
}
$event = json_decode($raw, true);
// De-dupe: cache 24h o event.id
if (cache()->has("zfiscoo:{$event['id']}")) {
return response()->json(['ok' => true, 'deduped' => true]);
}
cache()->put("zfiscoo:{$event['id']}", true, now()->addHours(24));
// dispatch async pra fila
\App\Jobs\ProcessZfiscooEvent::dispatch($event);
return response()->json(['ok' => true]);
});config/services.php
'zfiscoo' => [
'api_url' => env('ZFISCOO_API_URL'),
'api_key' => env('ZFISCOO_API_KEY'),
'issuer_id' => env('ZFISCOO_ISSUER_ID'),
'webhook_secret' => env('ZFISCOO_WEBHOOK_SECRET'),
],