The VedAstro Dart library gives you instant access to the world's most comprehensive Vedic astrology engine — planet positions, divisional charts, dasa periods, compatibility reports, and AI-powered features, all through a lightweight SDK.
Whether you're building a horoscope app, a matchmaking platform, or a research tool, VedAstro's Dart library removes every barrier between you and professional-grade Vedic astrology calculations. No complicated setup. No local binaries. No astrology expertise required to get started. Just install the library, set your API key, and start computing — the heavy lifting runs on VedAstro's cloud engine.
Hosted calculations for Vedic astrology applications
Ayanamsa systems — Lahiri, Raman, KP, Fagan-Bradley & 43 more
Divisional charts — full Parashari varga system coverage
Horoscope predictions and classical-text search
Everything runs in the cloud — your app stays lightweight
MIT licensed, community maintained, fully auditable on GitHub
The VedAstro Dart library is a thin, elegant wrapper around the VedAstro REST API. You write Dart; the cloud does the calculation.
The library itself is tiny — everything runs server-side
Calculation improvements roll out on the server automatically
From personal projects to production apps, same code works
Dart >=3.0.0 <4.0.0 and an internet connection

dependencies:
vedastro:
git:
url: https://github.com/VedAstro/VedAstro.Dart.gitAdd this Git dependency to pubspec.yaml, then run dart pub get. The package is not currently available on pub.dev. Calls are async; close the client when finished. Repository demos import support.dart, so run them from the cloned repository.
FreeAPIUser allows 5 requests per minute. Pace multi-call examples or use your subscription key. Locations take longitude before latitude.
Get unlimited access for just $1/month — no rate limits, all features included
Instant activation • Cancel anytime • 99.9% uptime guarantee
Start with one Sun-sign calculation using the free key.
import 'package:vedastro/vedastro.dart';
Future<void> main() async {
final client = VedAstroClient(apiKey: 'FreeAPIUser');
final birth = Time.of(
'14:30 25/10/1992 +05:30', // HH:mm dd/MM/yyyy +HH:mm
GeoLocation.of('Mumbai', 72.8777, 19.0760), // name, longitude, latitude
);
final sun = await client.calculate().planetRasiD1Sign(PlanetName.sun, birth);
print(Response.string(sun, 'Name')); // Libra
print(Response.string(sun, ['DegreesIn', 'DegreeMinuteSecond']));
client.close();
}Save as main.dart in your Dart project and run dart run main.dart.
Run from the cloned SDK repository; helper files are included there.
import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// Reads a full birth chart: every planet's sign, degree and constellation, plus the
/// house cusps.
///
/// dart run example/birth_chart_basics.dart
Future<void> main() async {
final client = demoClient();
final birth = demoBirth();
final pace = demoShouldPace(client);
demoHeading('Planets');
for (final planet in [
PlanetName.sun,
PlanetName.moon,
PlanetName.mars,
PlanetName.mercury,
PlanetName.jupiter,
PlanetName.venus,
PlanetName.saturn,
]) {
final result = await client.calculate().planetRasiD1Sign(planet, birth);
demoField(
planet.wireName,
'${Response.string(result, 'Name')} '
'${Response.string(result, ['DegreesIn', 'DegreeMinuteSecond'])}',
);
await demoPace(enabled: pace);
}
demoHeading('House signs');
for (final house in [
HouseName.house1,
HouseName.house4,
HouseName.house7,
HouseName.house10
]) {
final sign = await client.calculate().houseSignName(house, birth);
demoField(house.wireName, sign);
await demoPace(enabled: pace);
}
demoHeading('Constellations');
for (final planet in [PlanetName.sun, PlanetName.moon]) {
final star = await client.calculate().planetConstellation(planet, birth);
demoField(planet.wireName, star);
await demoPace(enabled: pace);
}
client.close();
}Run from the cloned SDK repository; helper files are included there.
import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// The five limbs of the day, plus the inauspicious windows that depend on sunrise.
///
/// dart run example/daily_panchanga.dart
Future<void> main() async {
final client = demoClient();
final now = Time.now(GeoLocation.of('Kuala Lumpur', 101.6869, 3.1390));
final pace = demoShouldPace(client);
demoHeading('Panchanga for ${now.stdTime}');
final tithi = await client.calculate().lunarDay(now);
demoField('Tithi', Response.string(tithi, 'Name'));
demoField('Paksha', Response.string(tithi, 'Paksha'));
demoField('Phase', Response.string(tithi, 'Phase'));
await demoPace(enabled: pace);
final yoga = await client.calculate().nithyaYoga(now);
demoField('Nithya yoga', Response.string(yoga, 'Name'));
await demoPace(enabled: pace);
final karana = await client.calculate().karana(now);
demoField('Karana', karana);
await demoPace(enabled: pace);
demoHeading('Sun and Rahu');
demoField('Sunrise', await client.calculate().sunriseTime(now));
await demoPace(enabled: pace);
demoField('Sunset', await client.calculate().sunsetTime(now));
await demoPace(enabled: pace);
demoField('Rahu kala', await client.calculate().rahuKala(now));
client.close();
}Remove rate limits and get instant access to all 684 calculations
| Category | What's Included |
|---|---|
| Positions, longitudes, strengths, aspects, conjunctions, retrograde status | |
| House signs, lords, bhava chart, all house data | |
| D1 through D60 — Navamsha, Drekkana, and all varga charts | |
| Sign-based calculations, planet-in-sign queries | |
| Vimshottari dasa periods with explicit starting rules and configurable depth | |
| Auspicious time finding, event predictions over any date range | |
| Kuta scoring, full compatibility reports, BaZi integration, AI chat analysis | |
| Birth time auto-fill from partial data, natural language horoscope search |
Full method reference: vedastro.org/API.html
Switch ayanamsa systems with SDK-specific settings
Modern Vedic standard
Classical Vedic system
KP System
Western sidereal
import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// Ayanamsa is the difference between the tropical and the sidereal zodiac, and the
/// choice shifts every position by up to a degree. VedAstro supports 47 systems.
///
/// dart run example/custom_ayanamsa.dart
Future<void> main() async {
final birth = demoBirth();
final base = demoClient();
demoHeading('The same moment, read four ways');
for (final ayanamsa in [
Ayanamsa.lahiri, // the Indian government standard
Ayanamsa.raman,
Ayanamsa.krishnamurti, // KP
Ayanamsa.faganBradley, // Western sidereal
]) {
// Drawn from the same environment, so the key and base URL are identical; only
// the ayanamsa differs. The ayanamsa travels with each request, so it is safe to
// keep several clients side by side.
final scoped = VedAstroClient(
apiKey: base.apiKey,
baseUrl: base.baseUrl,
silent: true,
defaultAyanamsa: ayanamsa,
);
final sun =
await scoped.calculate().planetRasiD1Sign(PlanetName.sun, birth);
final ayanamsaValue = await scoped.calculate().ayanamsaDegree(birth);
demoField(
ayanamsa.wireName,
'${Response.string(sun, 'Name')} '
'${Response.string(sun, ['DegreesIn', 'DegreeMinuteSecond'])} '
'| ayanamsa $ayanamsaValue',
);
scoped.close();
// Four clients x two calls each outruns the free tier; a paid key would not need
// this.
await demoPace(enabled: demoShouldPace(base));
}
demoHeading('Which ayanamsa is in force');
demoField('Client default', base.ayanamsa?.wireName ?? 'the API default');
demoField('Ayanamsas available', Ayanamsa.values.length);
base.close();
}Run this example inside the cloned repository. View source.
Rate-limited
'FreeAPIUser'
No signup required — ideal for exploration and development
Unlimited access
High-speed access to all 684 calculations for production apps
final client = VedAstroClient(apiKey: 'your-key-here');
Clone the repository to run these examples with their included helpers. Expand an example to read and copy its source.
import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// A batch of charts, paced for the free tier.
///
/// dart run example/batch_processing.dart
///
/// The point of this example is not the loop; it is what the loop does *not* do. The
/// SDK never retries and never throttles, so pacing is yours to own - and it has to
/// be central, because the per-key limit is shared across every process you run.
Future<void> main() async {
final client = demoClient();
final pace = demoShouldPace(client);
// A small set of people to chart.
final people = <String, Time>{
'Asha': Time.of(
'14:30 25/10/1992 +05:30',
GeoLocation.of('Mumbai', 72.8777, 19.0760),
),
'Bala': Time.of(
'06:45 02/07/1988 +08:00',
GeoLocation.of('Kuala Lumpur', 101.6869, 3.1390),
),
'Chen': Time.of(
'21:10 19/12/2000 +08:00',
GeoLocation.of('Singapore', 103.8198, 1.3521),
),
};
demoHeading('Ascendants');
for (final entry in people.entries) {
final sign =
await client.calculate().houseSignName(HouseName.house1, entry.value);
demoField(entry.key, sign);
// The free tier allows five calls a minute; a paid key does not need this.
await demoPace(enabled: pace);
}
demoHeading('Suns');
for (final entry in people.entries) {
final sun =
await client.calculate().planetRasiD1Sign(PlanetName.sun, entry.value);
demoField(entry.key, Response.string(sun, 'Name'));
await demoPace(enabled: pace);
}
// WHAT A PRODUCTION BATCH WOULD ADD ---------------------------------------
//
// - A CONCURRENCY LIMIT. Six calls at once is fine; six hundred is not. A
// fixed-size pool (or a package such as `pool`) keeps the pressure bounded.
//
// - A RETRY ON VedAstroException ONLY. That means the request never completed, so
// trying again is reasonable. An ApiException means the API rejected the call -
// repeating it verbatim will fail the same way.
//
// - CACHING KEYED BY THE CHART INPUT. `birth.stdTime` plus the location is the
// natural key; the same person is charted many times.
//
// - PROGRESS AND A FAILURE LIST, so one bad date does not abandon the whole run:
//
// final failures = <String, Object>{};
// for (final entry in people.entries) {
// try { ... } catch (failure) { failures[entry.key] = failure; }
// }
demoHeading('Done');
// ignore: avoid_print
print(' charted ${people.length} people, ${people.length * 2} calls');
client.close();
}import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// Reads a full birth chart: every planet's sign, degree and constellation, plus the
/// house cusps.
///
/// dart run example/birth_chart_basics.dart
Future<void> main() async {
final client = demoClient();
final birth = demoBirth();
final pace = demoShouldPace(client);
demoHeading('Planets');
for (final planet in [
PlanetName.sun,
PlanetName.moon,
PlanetName.mars,
PlanetName.mercury,
PlanetName.jupiter,
PlanetName.venus,
PlanetName.saturn,
]) {
final result = await client.calculate().planetRasiD1Sign(planet, birth);
demoField(
planet.wireName,
'${Response.string(result, 'Name')} '
'${Response.string(result, ['DegreesIn', 'DegreeMinuteSecond'])}',
);
await demoPace(enabled: pace);
}
demoHeading('House signs');
for (final house in [
HouseName.house1,
HouseName.house4,
HouseName.house7,
HouseName.house10
]) {
final sign = await client.calculate().houseSignName(house, birth);
demoField(house.wireName, sign);
await demoPace(enabled: pace);
}
demoHeading('Constellations');
for (final planet in [PlanetName.sun, PlanetName.moon]) {
final star = await client.calculate().planetConstellation(planet, birth);
demoField(planet.wireName, star);
await demoPace(enabled: pace);
}
client.close();
}import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// Every planet's sign right now, from one call.
///
/// dart run example/current_planets.dart
Future<void> main() async {
final client = demoClient();
// "Now" at the place you care about. The API needs a location, not just a time.
final now = Time.now(GeoLocation.of('Kuala Lumpur', 101.6869, 3.1390));
demoHeading('Now: ${now.stdTime}');
final signs = await client.calculate().allPlanetRasiSigns(now);
for (final entry in Response.list(signs, [])) {
demoField(
Response.string(entry, 'Planet'),
Response.string(entry, 'Sign'),
);
}
demoHeading('Full data for the Moon');
final moon = await client.calculate().allPlanetData(PlanetName.moon, now);
demoField('Sign', Response.string(moon, 'Sign'));
demoField('Constellation', Response.string(moon, 'Constellation'));
demoField(
'Degrees', Response.string(moon, ['DegreesIn', 'DegreeMinuteSecond']));
client.close();
}import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// Ayanamsa is the difference between the tropical and the sidereal zodiac, and the
/// choice shifts every position by up to a degree. VedAstro supports 47 systems.
///
/// dart run example/custom_ayanamsa.dart
Future<void> main() async {
final birth = demoBirth();
final base = demoClient();
demoHeading('The same moment, read four ways');
for (final ayanamsa in [
Ayanamsa.lahiri, // the Indian government standard
Ayanamsa.raman,
Ayanamsa.krishnamurti, // KP
Ayanamsa.faganBradley, // Western sidereal
]) {
// Drawn from the same environment, so the key and base URL are identical; only
// the ayanamsa differs. The ayanamsa travels with each request, so it is safe to
// keep several clients side by side.
final scoped = VedAstroClient(
apiKey: base.apiKey,
baseUrl: base.baseUrl,
silent: true,
defaultAyanamsa: ayanamsa,
);
final sun =
await scoped.calculate().planetRasiD1Sign(PlanetName.sun, birth);
final ayanamsaValue = await scoped.calculate().ayanamsaDegree(birth);
demoField(
ayanamsa.wireName,
'${Response.string(sun, 'Name')} '
'${Response.string(sun, ['DegreesIn', 'DegreeMinuteSecond'])} '
'| ayanamsa $ayanamsaValue',
);
scoped.close();
// Four clients x two calls each outruns the free tier; a paid key would not need
// this.
await demoPace(enabled: demoShouldPace(base));
}
demoHeading('Which ayanamsa is in force');
demoField('Client default', base.ayanamsa?.wireName ?? 'the API default');
demoField('Ayanamsas available', Ayanamsa.values.length);
base.close();
}import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// The five limbs of the day, plus the inauspicious windows that depend on sunrise.
///
/// dart run example/daily_panchanga.dart
Future<void> main() async {
final client = demoClient();
final now = Time.now(GeoLocation.of('Kuala Lumpur', 101.6869, 3.1390));
final pace = demoShouldPace(client);
demoHeading('Panchanga for ${now.stdTime}');
final tithi = await client.calculate().lunarDay(now);
demoField('Tithi', Response.string(tithi, 'Name'));
demoField('Paksha', Response.string(tithi, 'Paksha'));
demoField('Phase', Response.string(tithi, 'Phase'));
await demoPace(enabled: pace);
final yoga = await client.calculate().nithyaYoga(now);
demoField('Nithya yoga', Response.string(yoga, 'Name'));
await demoPace(enabled: pace);
final karana = await client.calculate().karana(now);
demoField('Karana', karana);
await demoPace(enabled: pace);
demoHeading('Sun and Rahu');
demoField('Sunrise', await client.calculate().sunriseTime(now));
await demoPace(enabled: pace);
demoField('Sunset', await client.calculate().sunsetTime(now));
await demoPace(enabled: pace);
demoField('Rahu kala', await client.calculate().rahuKala(now));
client.close();
}import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// Divisional (varga) charts: the same moment read at finer resolutions.
///
/// dart run example/divisional_charts.dart
Future<void> main() async {
final client = demoClient();
final birth = demoBirth();
final pace = demoShouldPace(client);
demoHeading('Navamsha (D9)');
for (final planet in [PlanetName.sun, PlanetName.moon, PlanetName.jupiter]) {
final sign = await client.calculate().planetNavamshaD9Sign(planet, birth);
demoField(planet.wireName, Response.string(sign, 'Name'));
await demoPace(enabled: pace);
}
demoHeading('Every planet, one division at a time');
demoField(
'Navamsha D9',
demoTruncate(await client.calculate().allPlanetNavamshaSign(birth), 90),
);
await demoPace(enabled: pace);
demoField(
'Dashamamsha D10',
demoTruncate(await client.calculate().allPlanetDashamamshaSign(birth), 90),
);
await demoPace(enabled: pace);
demoField(
'Dwadashamsha D12',
demoTruncate(await client.calculate().allPlanetDwadashamshaSign(birth), 90),
);
client.close();
}import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// Every way a call can fail, and what each one tells you.
///
/// dart run example/error_handling.dart
Future<void> main() async {
final client = demoClient();
final birth = demoBirth();
// 1. Client-side validation fails before any network call, which is the cheapest
// possible failure: no request, no rate-limit cost, a message naming the field.
demoHeading('1. Validation, before the network');
for (final attempt in <void Function()>[
() =>
Time.of('25/10/1992 14:30', GeoLocation.of('Mumbai', 72.8777, 19.0760)),
() => Time.of(
'10:00 31/02/2020 +00:00', GeoLocation.of('Mumbai', 72.8777, 19.0760)),
() => GeoLocation.of('Swapped', 19.0760, 72.8777),
]) {
try {
attempt();
// ignore: avoid_print
print(' ✗ accepted something it should have rejected');
} on ArgumentError catch (failure) {
// ignore: avoid_print
print(' ✓ rejected: ${failure.message}');
}
}
// 2. An ApiException means the API answered and rejected the call. Retrying the
// identical request will not help.
demoHeading('2. The API rejected the call');
try {
// An intentionally unknown endpoint.
await client.call('NoSuchCalculatorExists', parameters: {'time': birth});
} on ApiException catch (failure) {
demoField('Type', 'ApiException');
demoField('Endpoint', failure.endpoint);
demoField('HTTP status', failure.statusCode);
demoField('Message', demoTruncate(failure.message, 100));
}
// 3. A VedAstroException means the request never completed - DNS, TLS, a reset
// connection. This is the one worth retrying.
demoHeading('3. The request never completed');
final unreachable = VedAstroClient(
apiKey: client.apiKey,
baseUrl: 'https://not-a-real-vedastro-host.test/api/Calculate',
silent: true,
timeout: const Duration(seconds: 5),
);
try {
await unreachable.calculate().planetRasiD1Sign(PlanetName.sun, birth);
} on VedAstroException catch (failure) {
demoField('Type', failure.runtimeType.toString());
demoField('Message', demoTruncate(failure.message, 100));
} finally {
unreachable.close();
}
// 4. The API key never appears in a message, so an exception is safe to log.
demoHeading('4. The key is redacted');
// ignore: avoid_print
print(' configured key: ${client.apiKey.isEmpty ? "(none)" : "[present]"}');
try {
await client.call('NoSuchCalculatorExists', parameters: {'time': birth});
} on ApiException catch (failure) {
final leaks =
client.apiKey.isNotEmpty && failure.toString().contains(client.apiKey);
// ignore: avoid_print
print(' ${leaks ? "✗ LEAKED" : "✓ not present in the message"}');
}
client.close();
}import 'dart:io';
import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// Runs the whole stack against the real API, through the real HTTP transport.
///
/// Unlike the test suite - which uses a fake transport and needs no network - this
/// spends real API calls, so it is deliberately not part of CI.
///
/// dart run example/live_check.dart
///
/// Set `VEDASTRO_API_KEY` to use a paid key; otherwise the free tier applies and the
/// checks pace themselves.
Future<void> main() async {
final client = demoClient(silent: false);
final birth = demoBirth();
final pace = demoShouldPace(client);
final transport =
client.timeout == null ? 'stream (no deadline)' : 'with a deadline';
// ignore: avoid_print
print('VedAstro Dart SDK — live check against ${client.baseUrl}');
// ignore: avoid_print
print('transport: $transport\n');
var failures = 0;
Future<void> check(String label, Future<Object?> Function() action) async {
try {
final result = await action();
// ignore: avoid_print
print(' ✓ ${label.padRight(14)} $result');
} catch (failure) {
failures++;
// ignore: avoid_print
print(' ✗ ${label.padRight(14)} $failure');
}
await demoPace(enabled: pace);
}
await check('Sun sign', () async {
final sun =
await client.calculate().planetRasiD1Sign(PlanetName.sun, birth);
return '${Response.string(sun, 'Name')} at '
'${Response.string(sun, ['DegreesIn', 'DegreeMinuteSecond'])}';
});
await check('Ascendant', () async {
final sign =
await client.calculate().houseSignName(HouseName.house1, birth);
return sign;
});
await check('Panchanga', () async {
final tithi = await client.calculate().lunarDay(birth);
return '${Response.string(tithi, 'Name')} (${Response.string(tithi, 'Paksha')})';
});
await check('Numerology', () async {
final number = await client.calculate().birthNumber(birth);
return 'birth number $number';
});
await check('Constellation', () async {
final star =
await client.calculate().planetConstellation(PlanetName.moon, birth);
return star;
});
await check('RAG search', () async {
final passages = await client
.calculate()
.searchSourceText('effects of Saturn in the 7th house');
return '${Response.count(passages, [])} passage(s)';
});
client.close();
// ignore: avoid_print
print('');
if (failures > 0) {
// ignore: avoid_print
print('$failures live check(s) failed.');
exitCode = 1;
return;
}
// ignore: avoid_print
print('All live checks passed.');
}import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// Numerology: the numbers derived from a birth moment and a name.
///
/// dart run example/numerology.dart
Future<void> main() async {
final client = demoClient();
final birth = demoBirth();
demoHeading('From the birth moment');
demoField('Birth number', await client.calculate().birthNumber(birth));
demoField('Destiny number', await client.calculate().destinyNumber(birth));
demoHeading('From a name');
final prediction =
await client.calculate().nameNumberPrediction('Ada Lovelace');
demoField(
'Name number', Response.get(prediction, 'NameNumber') ?? prediction);
demoField('Meaning', Response.string(prediction, 'Meaning'));
client.close();
}import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// The smallest useful program: one client, one moment, one calculation.
///
/// dart run example/quick_start.dart
Future<void> main() async {
final client = demoClient();
final birth = demoBirth();
demoHeading('Position of the Sun');
final sun = await client.calculate().planetRasiD1Sign(PlanetName.sun, birth);
demoField('Sign', Response.string(sun, 'Name'));
demoField('Degrees in sign',
Response.string(sun, ['DegreesIn', 'DegreeMinuteSecond']));
demoHeading('Ascendant');
final ascendant =
await client.calculate().houseSignName(HouseName.house1, birth);
demoField('Rising sign', ascendant);
client.close();
}import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// Semantic search across classical Vedic texts, so an answer can be grounded in a
/// source rather than in a model's memory.
///
/// dart run example/rag_vedic_books.dart
Future<void> main() async {
final client = demoClient();
final pace = demoShouldPace(client);
demoHeading('Which texts are indexed');
final sources = await client.calculate().getAvailableSourceTexts();
for (final source in Response.list(sources, [])) {
// Each entry is a name and the number of chunks indexed for it.
// ignore: avoid_print
print(' - $source');
}
await demoPace(enabled: pace);
const question = 'effects of Saturn in the seventh house';
demoHeading('Searching: "$question"');
final passages = await client.calculate().searchSourceText(question, topK: 3);
for (final passage in Response.list(passages, [])) {
demoField('Source', Response.string(passage, 'sourceName'));
demoField('Page', Response.intValue(passage, 'pageNumber'));
demoField('Score', Response.doubleValue(passage, 'score'));
// ignore: avoid_print
print(' ${demoTruncate(Response.string(passage, 'text'), 220)}\n');
}
client.close();
}import 'dart:convert';
import 'dart:io';
import 'package:vedastro/vedastro.dart';
import 'support.dart';
/// How to use the SDK inside a long-running server.
///
/// This file is written to be **read** — the handler below is the shape you would
/// paste into a Shelf, Dart Frog or `HttpServer` app. Run it to see the same logic
/// print its answers instead of serving them:
///
/// dart run example/server_usage.dart
Future<void> main() async {
// ONE CLIENT, CREATED ONCE -------------------------------------------------
//
// The client is immutable and holds no per-request state, so build it when the
// isolate starts and share it. Building one per request would throw away the
// connection pool and add a TLS handshake to every call.
//
// `silent: true` matters on a server: the start-up banner would otherwise be
// written into a response body.
final vedAstro = VedAstroClient.fromEnvironment(
Platform.environment,
silent: true,
);
// WHAT A HANDLER LOOKS LIKE ------------------------------------------------
Future<(int, String)> sunSignHandler(Map<String, String> query) async {
try {
final birth = Time.of(
query['when']!,
GeoLocation.of(
'query',
double.parse(query['lon']!),
double.parse(query['lat']!),
),
);
final result = await vedAstro.calculate().planetRasiD1Sign(
PlanetName.sun,
birth,
);
return (200, jsonEncode({'sign': Response.string(result, 'Name')}));
} on ArgumentError catch (failure) {
// The caller sent something malformed. Their fault, and cheap to answer.
return (400, jsonEncode({'error': failure.message}));
} on ApiException catch (failure) {
// The API answered and rejected the call. Do not retry the same request.
stderr.writeln(failure); // the key is already redacted
return (502, jsonEncode({'error': 'upstream rejected the request'}));
} on VedAstroException catch (failure) {
// The request never completed. This one is worth a bounded retry.
stderr.writeln(failure);
return (503, jsonEncode({'error': 'upstream unavailable'}));
}
}
// The rest of this file just drives that handler so the output is visible.
demoHeading('A well-formed request');
final ok = await sunSignHandler({
'when': '14:30 25/10/1992 +05:30',
'lon': '72.8777',
'lat': '19.0760',
});
demoField('status', ok.$1);
demoField('body', ok.$2);
demoHeading('A malformed request');
final bad = await sunSignHandler({
'when': '25/10/1992 14:30', // the wrong date order
'lon': '72.8777',
'lat': '19.0760',
});
demoField('status', bad.$1);
demoField('body', demoTruncate(bad.$2, 90));
// NOTES WORTH KEEPING ------------------------------------------------------
//
// - NO REQUEST TIMEOUT is applied by default, on purpose. A calculation can take
// minutes, and a fixed deadline would only ever truncate a valid answer. Set
// `timeout: const Duration(seconds: 30)` only when your own request budget
// demands one.
//
// - CACHE BY CHART INPUT. The same birth details recur constantly, and a cache hit
// costs no API calls at all. A `Map` keyed by the wire time string is enough to
// start; move it to Redis when you run more than one isolate.
//
// - THE FREE TIER IS 5 CALLS PER MINUTE, counted per key across every process. Pace
// centrally rather than per isolate, or two workers will throttle each other.
//
// - RETRY ONLY VedAstroException, and only a bounded number of times with backoff.
// An ApiException means the API actively rejected the call.
//
// - CALL close() ON SHUTDOWN so the HTTP client's connections are released.
//
// - THROW AWAY NOTHING. The SDK never retries and never throttles, so your queue,
// your framework and your observability see exactly what the API did.
demoHeading('Shutting down');
vedAstro.close();
// ignore: avoid_print
print(' client closed');
}import 'dart:io';
import 'package:vedastro/vedastro.dart';
/// Shared helpers for the examples in this folder.
///
/// Every example is a standalone program: `dart run example/quick_start.dart`.
/// They default to the free tier, and honour two environment variables:
///
/// - `VEDASTRO_API_KEY` — use your own key instead of the free tier.
/// - `VEDASTRO_BASE_URL` — point at a different Calculate service.
///
/// The free tier allows five calls per minute, so the examples that make several
/// calls pace themselves with [demoPace].
const double demoFreeTierGapSeconds = 13.0;
/// Builds a client for the examples.
///
/// The banner is silenced by default: in a server it would corrupt a response body,
/// and in a demo it is noise.
VedAstroClient demoClient({bool silent = true}) {
final client =
VedAstroClient.fromEnvironment(Platform.environment, silent: silent);
return client;
}
/// A birth moment to calculate with: Mumbai, 25 October 1992 at 14:30 IST.
Time demoBirth() => Time.of(
'14:30 25/10/1992 +05:30',
GeoLocation.of('Mumbai', 72.8777, 19.0760),
);
/// A second birth moment, for the compatibility example.
Time demoPartner() => Time.of(
'09:15 12/03/1995 +05:30',
GeoLocation.of('Delhi', 77.2090, 28.6139),
);
/// Prints a section heading so the output of a demo is easy to scan.
void demoHeading(String title) {
// ignore: avoid_print
print('\n── $title');
}
/// Prints a labelled line.
void demoField(String label, Object? value) {
// ignore: avoid_print
print(' ${label.padRight(18)} $value');
}
/// Waits out the free tier's per-minute allowance.
///
/// `usleep` rather than `sleep` is not needed in Dart, but the gap is: the limit is
/// counted per key across every process, so a tight loop fails even on one machine.
Future<void> demoPace({bool enabled = true}) async {
if (!enabled) return;
await Future<void>.delayed(
Duration(milliseconds: (demoFreeTierGapSeconds * 1000).round()),
);
}
/// Whether the examples should pace themselves, which they skip for a paid key.
bool demoShouldPace(VedAstroClient client) => !client.hasApiKey;
/// Truncates long text so a demo's output stays readable.
String demoTruncate(Object? value, [int limit = 120]) {
final text = value?.toString() ?? '';
return text.length <= limit ? text : '${text.substring(0, limit)}...';
}
The VedAstro Dart library is fully open source under the MIT License. You can read the code, verify every API call, and contribute improvements back to the community. The library is maintained alongside the main VedAstro engine — when new calculations are added to the API, the Dart wrapper updates to match.
Note: Calculator wrappers are generated to follow the hosted API. See the repository for source, generator guidance, and contribution instructions.
Install the library, try the free tier, and see how fast you can go from zero to a working Vedic astrology application. When your project is ready for the real world, your API key is one click away.
dart pub get
Made and funded by users — Support VedAstro