Browse documentation

Dart & Flutter SDK

The official nRouter Dart & Flutter SDK with cross-platform support for web, mobile, and desktop, SSE streaming, and typed errors.

Last updated

The official nRouter Dart SDK (nrouter) provides cross-platform support for Flutter mobile, desktop, web, and standalone Dart VM applications. With a single lightweight dependency on http, it connects to https://api.nrouter.ai/v1 and delivers automated metadata extraction, Server-Sent Events (SSE) streaming, and sealed error types.

Installation

Add nrouter to your project dependencies:

dart pub add nrouter
# or for Flutter projects:
flutter pub add nrouter

Or add it directly to your pubspec.yaml:

dependencies:
  nrouter: ^3.1.2

Setup & Authentication

Pass your virtual API key directly to the NRouter client:

import 'package:nrouter/nrouter.dart';

final client = NRouter(apiKey: 'sk-nrouter-your-api-key-here');

For command-line Dart VM applications, configure the environment variable:

export NROUTER_API_KEY="sk-nrouter-your-api-key-here"

Then read it in your CLI app:

import 'dart:io';
import 'package:nrouter/nrouter.dart';

final client = NRouter(apiKey: Platform.environment['NROUTER_API_KEY']!);

The client connects to https://api.nrouter.ai/v1 by default. Custom endpoints can be passed via baseUrl:

final client = NRouter(
  apiKey: 'sk-nrouter-your-api-key-here',
  baseUrl: 'https://api.nrouter.ai/v1',
);

Key Safety in Flutter Applications

In Flutter mobile and web apps, Platform.environment does not supply shell environment variables (dart:io is unavailable on web). Furthermore, any key compiled into a mobile binary or served on the web is visible to anyone inspecting network requests or decompiling the client bundle. Always mint short-lived virtual keys from your backend service rather than bundling root credentials.

Quickstart

Send a chat completion request and read the response:

import 'package:nrouter/nrouter.dart';

Future<void> main() async {
  final client = NRouter(apiKey: 'sk-nrouter-your-api-key-here');

  final result = await client.chatCompletions({
    'model': 'gpt-5.4-mini',
    'messages': [
      {'role': 'user', 'content': 'Hello!'}
    ],
  });

  print(result.body['choices']);

  if (result.meta.isPriced) {
    print('Cost: \$${result.meta.cost}');
  }

  client.close();
}

Streaming

Stream responses in real-time using asynchronous streams:

await for (final chunk in client.messagesStream({
  'model': 'claude-haiku-4-5-20251001',
  'max_tokens': 64,
  'messages': [
    {'role': 'user', 'content': 'Hello!'}
  ],
})) {
  print(chunk.delta);
}

Cancelling stream subscription stops consumption of the underlying HTTP stream immediately.

Error Handling

All gateway refusals map to subclasses of the sealed NRouterError hierarchy:

try {
  await client.chatCompletions(body);
} on NRouterGuardrailBlockedError catch (e) {
  print('Blocked by guardrail: ${e.message}');
} on NRouterCreditError catch (e) {
  print('Out of credits: ${e.message}');
} on NRouterRateLimitError catch (e) {
  if (e.isRetryable) {
    print('Rate limit hit; retryable after backoff');
  }
}
TypeHTTP StatusDescription
NRouterRequestError400Invalid payload or missing parameters
NRouterGuardrailBlockedError400Request blocked by active guardrail checks
NRouterAuthenticationError401Invalid or revoked virtual key
NRouterCreditError402Insufficient balance or budget limit reached
NRouterNotFoundError404Model not found
NRouterRateLimitError429Rate limit or TPM quota exceeded
NRouterServiceError503Gateway or upstream service error
NRouterTransportErrorNetwork connection failure

isRetryable is true only for NRouterRateLimitError, NRouterServiceError, and NRouterTransportError.

Response Metadata & Cost Tracking

result.meta extracts all x-nr-* gateway response headers into strongly-typed properties:

final meta = result.meta;
print('Request ID: ${meta.requestId}');
print('Model: ${meta.model}');
print(meta.isPriced ? 'Cost: \$${meta.cost}' : 'Cost: unpriced');

Source & Repository

The source code and runnable demonstrations are available on GitHub:

Was this page helpful?