Manual Failure Capture
Capture API failures without using the Dio interceptor — ideal for custom request routing or non-Dio HTTP clients.
When to Use Manual Capture
- Your app uses a custom request routing system
- You're using an HTTP client other than Dio
- You want fine-grained control over which failures to capture
- You need to capture failures from an offline queue system
Basic Usage
Use captureFailure() to manually report a failed request:
await EndpointVault.instance.captureFailure(
method: 'POST',
url: 'https://api.example.com/items',
statusCode: 500,
errorMessage: 'Internal Server Error',
requestBody: {'name': 'Item 1', 'price': 29.99},
requestHeaders: {'Authorization': 'Bearer ***'},
responseBody: {'error': 'Database connection failed'},
);
Full Parameter Reference
await EndpointVault.instance.captureFailure(
// Required
method: 'POST', // HTTP method
url: 'https://api.example.com/endpoint',
statusCode: 500, // Response status code (nullable)
// Optional - Error details
errorType: 'server_error', // Category of error
errorMessage: 'Internal Server Error',
// Optional - Request data (will be redacted & encrypted)
requestHeaders: {'Content-Type': 'application/json'},
requestBody: {'key': 'value'},
// Optional - Response data (will be redacted & encrypted)
responseHeaders: {'X-Request-Id': 'abc123'},
responseBody: {'error': 'Something went wrong'},
// Optional - Timing
duration: Duration(milliseconds: 1500),
// Optional - Extra metadata (not encrypted, for filtering)
extra: {
'userId': 123,
'feature': 'checkout',
'retryCount': 2,
},
);
Integration with Offline Queue
A common pattern is to capture failures when requests fail after being retried from an offline queue:
class OfflineQueueManager {
Future<void> processRequest(QueuedRequest request) async {
try {
final response = await executeRequest(request);
await handleSuccess(request, response);
} catch (e) {
final statusCode = (e is DioException) ? e.response?.statusCode : null;
// Check if this is a non-retryable error
if (!isRetryable(statusCode)) {
await quarantineFailedRequest(request, statusCode);
}
}
}
Future<void> quarantineFailedRequest(
QueuedRequest request,
int? statusCode,
) async {
// Capture failure with EndpointVault
await EndpointVault.instance.captureFailure(
method: request.method,
url: request.url,
statusCode: statusCode,
requestBody: request.data,
requestHeaders: request.headers,
extra: {
'requestType': request.type.name,
'queuedAt': request.createdAt.toIso8601String(),
},
);
// Remove from local queue
await removeFromQueue(request);
}
}
Tip: The
extra field is useful for storing metadata for filtering in the dashboard, like user IDs or feature names.
Enabling Replay Support
To enable device-side replay for manually captured failures, configure onReplayRequest during SDK initialization. This callback handles all replay requests — including post-replay operations like file uploads:
await EndpointVault.init(
apiKey: 'your-api-key',
encryptionKey: 'your-32-char-key',
onReplayRequest: (eventId, request) async {
// Re-execute the request
final response = await dio.request(
request.url,
data: request.requestBody,
options: Options(method: request.method),
);
// Handle any post-replay operations here
// For example, if the response contains upload URLs:
if (response.data['uploadUrls'] != null) {
await uploadPendingFiles(response.data['uploadUrls']);
}
return response;
},
);
See Device-side Replay for more details on the replay flow.
