authnet_server 1.0.2
authnet_server: ^1.0.2 copied to clipboard
Authorize.Net webhooks for Dart servers: HMAC-SHA512 verification, management, notification history, retries. Not affiliated with or endorsed by Authorize.Net or Visa.
example/authnet_server_example.dart
// Runnable example: a tiny HTTP server that receives Authorize.Net webhook
// deliveries, verifies their signature, and parses the event.
//
// dart run example/authnet_server_example.dart
//
// Then, from another terminal, send it a signed test delivery:
// dart run example/authnet_server_example.dart --send-test
//
// This demo uses a fixed, made-up hex signature key so the two commands
// above work out of the box with no setup. For your real webhook endpoint,
// swap `_demoSignatureKey` for your actual Signature Key (from the
// Authorize.Net Merchant Interface under Account > Settings > Security
// Settings > General Security Settings > API Credentials and Keys), read
// from an environment variable, never hardcoded. This example never talks
// to Authorize.Net itself: it only demonstrates verifying and parsing a
// delivery you'd receive at a real webhook endpoint.
import 'dart:convert';
import 'dart:io';
import 'package:authnet_server/authnet_server.dart';
import 'package:crypto/crypto.dart';
const _port = 8787;
// A real Signature Key from the Authorize.Net Merchant Interface is a
// 128-character hex string; this shorter, made-up one is just for the
// demo, matched on both the "server" and "--send-test" sides below.
const _demoSignatureKey =
'0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF';
Future<void> main(List<String> args) async {
if (args.contains('--send-test')) {
await _sendTestDelivery();
return;
}
final signatureKey =
Platform.environment['AUTHNET_SIGNATURE_KEY'] ?? _demoSignatureKey;
final server = await HttpServer.bind(InternetAddress.loopbackIPv4, _port);
stdout.writeln('Listening on http://localhost:$_port. Ctrl+C to stop.');
stdout.writeln(
'In another terminal: dart run example/authnet_server_example.dart --send-test');
await for (final request in server) {
if (request.method != 'POST') {
request.response.statusCode = 405;
await request.response.close();
continue;
}
final rawBody = await utf8.decodeStream(request);
final signatureHeader = request.headers.value('X-ANET-Signature') ?? '';
final isValid = verifyWebhookSignature(
rawBody: rawBody,
signatureHeader: signatureHeader,
signatureKey: signatureKey,
);
if (!isValid) {
stdout.writeln('Rejected a delivery with an invalid signature.');
request.response.statusCode = 401;
await request.response.close();
continue;
}
final event = parseWebhookEvent(rawBody);
stdout.writeln('Verified event: ${event.eventType} '
'(notificationId: ${event.notificationId}, entityId: ${event.entityId})');
request.response.statusCode = 200;
await request.response.close();
}
}
/// Sends this process's own signed test delivery to the running server, so
/// you can see verification succeed without waiting for a real Authorize.Net
/// sandbox event.
Future<void> _sendTestDelivery() async {
const body = '{'
'"notificationId":"demo-1",'
'"eventType":"net.authorize.payment.authcapture.created",'
'"eventDate":"2026-08-24T10:00:00Z",'
'"webhookId":"wh_demo",'
'"payload":{"id":"60123456789"}'
'}';
final digest = Hmac(sha512, _decodeHex(_demoSignatureKey)).convert(
utf8.encode(body),
);
final client = HttpClient();
final request =
await client.postUrl(Uri.parse('http://localhost:$_port/webhooks'));
request.headers.set('X-ANET-Signature', 'sha512=${digest.toString()}');
request.write(body);
final response = await request.close();
stdout.writeln('Server responded: ${response.statusCode}');
client.close();
}
List<int> _decodeHex(String hex) {
final bytes = <int>[];
for (var i = 0; i < hex.length; i += 2) {
bytes.add(int.parse(hex.substring(i, i + 2), radix: 16));
}
return bytes;
}