Skip to content

Commit edfc7e1

Browse files
committed
docs: most-used endpoints across all 18 domains composed from one location lookup and verified against production, AGENTS task table in catalog order with the error table and gotchas in sync, llms-full error codes aligned
1 parent 255cecb commit edfc7e1

3 files changed

Lines changed: 352 additions & 203 deletions

File tree

‎AGENTS.md‎

Lines changed: 72 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,26 @@ var roxy = new RoxyClient(Environment.GetEnvironmentVariable("ROXY_API_KEY")!);
2222

2323
Get these and the generated types do the rest.
2424

25-
- **The fluent path mirrors the URL.** `GET /astrology/horoscope/{sign}/daily` is `roxy.Astrology.Horoscope["aries"].Daily.GetAsync()`. Each path segment is a property; each `{param}` is an indexer. Type `roxy.` and let IntelliSense walk the tree. Never invent a method name.
25+
- **The fluent path mirrors the URL.** `GET /astrology/horoscope/{sign}/daily` is `roxy.Astrology.Horoscope["aries"].Daily.GetAsync()`. Each path segment is a property; each `{param}` is an indexer. Type `roxy.` and let IntelliSense walk the tree. Never invent a method name, and never derive one from the `operationId` in the spec: this SDK is path-fluent, not operation-named.
2626
- **Request bodies use a target-typed `new()`.** `await roxy.Astrology.NatalChart.PostAsync(new() { Date = new Date(1990, 1, 15), ... })`. The type is inferred from the method, so you never need to name it; IntelliSense shows every field on `new() {`.
2727
- **Query parameters use a configuration lambda.** `await roxy.Crystals.Search.GetAsync(c => c.QueryParameters.Q = "amethyst");`. Multiple: `c => { c.QueryParameters.Limit = 20; c.QueryParameters.Offset = 0; }`.
2828
- **Always `await`, and catch `RoxyError`.** There is no result-wrapper object. The call returns the typed response directly and throws `RoxyError` (a subclass of `ApiException`) on failure. Switch on `e.Code`, not `e.Message`.
29-
- **Never hand-roll HttpClient.** `new RoxyClient(key)` injects auth, base URL, retries, and typed responses.
29+
- **Never hand-roll HttpClient.** `new RoxyClient(key)` injects auth, the base URL, typed responses, and a retry with backoff on a 429 or 503. Response field names come from the response schema of the spec and are PascalCase properties; the compiler catches any invented field, so if the build fails on a property, the field does not exist.
3030

3131
## Critical rule: geocode before any chart endpoint
3232

3333
Every chart, horoscope, panchang, dasha, dosha, navamsa, KP, synastry, compatibility, and natal endpoint needs `Latitude`, `Longitude`, and (for Western) `Timezone`. **Never ask the user for coordinates.** Call `roxy.Location.Search` first.
3434

3535
```csharp
36-
var search = await roxy.Location.Search.GetAsync(c => c.QueryParameters.Q = "Berlin");
37-
var city = search!.Cities![0];
38-
// city.Timezone is the IANA string ("Europe/Berlin"); pass it straight into a chart call and
39-
// the server resolves the DST-correct offset for the chart date. city.UtcOffset (5.5, -5, ...)
40-
// is the decimal equivalent.
36+
var place = await roxy.Location.Search.GetAsync(c => c.QueryParameters.Q = "New York");
37+
var city = place!.Cities![0];
38+
// city.Timezone is the IANA string ("America/New_York"). Pass it straight into any chart
39+
// endpoint and the server resolves it to the DST-correct decimal offset using the Date of
40+
// the chart itself, so a January 1990 New York chart picks EST (-5) even when you looked
41+
// the city up in July. city.UtcOffset (5.5, -5, 9, ...) also works and produces identical charts.
4142
```
4243

43-
`Q` accepts a bare city (`"Paris"`), city plus country (`"Berlin Germany"`), or comma-qualified (`"Springfield, Illinois"`). Use the qualified form to disambiguate.
44+
`Q` accepts a bare city (`"Paris"`), city plus country (`"Berlin Germany"`), or comma-qualified (`"Springfield, Illinois"`). Use the qualified form to disambiguate same-named cities.
4445

4546
## Domains
4647

@@ -74,19 +75,23 @@ var city = search!.Cities![0];
7475
### Two-step pattern for coordinate-dependent endpoints
7576

7677
```csharp
77-
var search = await roxy.Location.Search.GetAsync(c => c.QueryParameters.Q = "London");
78-
var city = search!.Cities![0];
78+
var place = await roxy.Location.Search.GetAsync(c => c.QueryParameters.Q = "London");
79+
var city = place!.Cities![0];
80+
var latitude = city.Latitude;
81+
var longitude = city.Longitude;
82+
var timezone = city.Timezone;
83+
var birthDate = new Date(1990, 1, 15);
84+
var birthTime = new Time(14, 30, 0);
7985

8086
var chart = await roxy.Astrology.NatalChart.PostAsync(new()
8187
{
82-
Date = new Date(1990, 1, 15),
83-
Time = new Time(14, 30, 0),
84-
Latitude = city.Latitude,
85-
Longitude = city.Longitude,
86-
Timezone = new() { String = city.Timezone },
88+
Date = birthDate, Time = birthTime,
89+
Latitude = latitude, Longitude = longitude, Timezone = new() { String = timezone },
8790
});
8891
```
8992

93+
One lookup feeds every domain. Request bodies are distinct generated types, so capture the five values once as locals and assign them into each body. The same `Date`, `Time`, `Latitude`, `Longitude` and `Timezone` are the body for `Astrology.NatalChart`, `VedicAstrology.BirthChart`, `VedicAstrology.Dasha.Current`, `Ayurveda.Constitution` and the `BirthData` of `Forecast.Transits`; the instant alone (`Date`, `Time`, `Timezone`) is the body for `HumanDesign.Bodygraph`, `ChineseAstrology.Bazi.Chart` and `Kabbalah.BirthProfile`. Never look the city up twice for one person.
94+
9095
### GET endpoints: path params are indexers, query params use the lambda
9196

9297
```csharp
@@ -102,8 +107,8 @@ Most valuable endpoints (charts, spreads, calculations) are POST:
102107
```csharp
103108
await roxy.VedicAstrology.BirthChart.PostAsync(new()
104109
{
105-
Date = new Date(1990, 1, 15), Time = new Time(14, 30, 0),
106-
Latitude = 28.6139, Longitude = 77.209, Timezone = new() { Double = 5.5 },
110+
Date = birthDate, Time = birthTime,
111+
Latitude = latitude, Longitude = longitude, Timezone = new() { String = timezone },
107112
});
108113

109114
await roxy.Tarot.Spreads.CelticCross.PostAsync(new() { Question = "What should I focus on?" });
@@ -123,11 +128,9 @@ Supported: astrology, vedicAstrology, forecast, humanDesign, chineseAstrology, f
123128

124129
### Error handling
125130

126-
Calls throw `RoxyError` (extends `ApiException`) on a 4xx or 5xx. `Message` is human-readable and may change; `Code` is stable, switch on it.
131+
Calls throw `RoxyError` (in `RoxyApi.Models`, extends `ApiException`) on a 4xx or 5xx. `Message` is human-readable and may change; `Code` is stable, switch on it.
127132

128133
```csharp
129-
using RoxyApi.Models;
130-
131134
try
132135
{
133136
var horoscope = await roxy.Astrology.Horoscope["aries"].Daily.GetAsync();
@@ -147,7 +150,9 @@ catch (RoxyError e)
147150
| 401 | `invalid_api_key` | Key format invalid or tampered |
148151
| 401 | `subscription_not_found` | Key references a non-existent subscription |
149152
| 401 | `subscription_inactive` | Subscription cancelled, expired, or suspended |
153+
| 401 | `api_key_revoked` | Key was deleted from the account |
150154
| 404 | `not_found` | Resource not found |
155+
| 4xx | `bad_request` and other status-derived codes | A client error the endpoint itself detected, such as a date window whose `endDate` precedes `startDate` |
151156
| 429 | `rate_limit_exceeded` | Monthly quota reached |
152157
| 500 | `internal_error` | Server error |
153158

@@ -157,49 +162,75 @@ Responses are fully typed objects, not dictionaries. Discover fields with Intell
157162

158163
- **City** (`Location.Search` -> `Cities[i]`): `City` (the name), `Country`, `Province`, `Latitude`, `Longitude`, `Timezone` (IANA), `UtcOffset` (decimal), `Population`.
159164
- **Natal chart**: `Planets`, `Houses`, `Aspects`, `Ascendant`, `Midheaven`, `Summary`. Each planet has `Name`, `Sign`, `Degree`, `House`, `IsRetrograde`. The `Planets` list has more than ten entries (classical bodies plus nodes and key points).
165+
- **Maps keyed by name** arrive in `AdditionalData`, not as properties. The Vedic kundli `Meta` (one entry per planet: `rashi`, `nakshatra`, `longitude`) and the biorhythm reading `Cycles` (one entry per cycle: `value`, `rawValue`, `phase`) are objects whose keys the spec leaves open, so the generated class has no fields of its own: read `kundli.Meta!.AdditionalData["Moon"]`, which is an `UntypedObject` from `Microsoft.Kiota.Abstractions.Serialization`, and call `GetValue()` on it for the inner dictionary.
160166

161167
```csharp
162-
var chart = await roxy.Astrology.NatalChart.PostAsync(new() { Date = new Date(1990, 1, 15), Time = new Time(14, 30, 0), Latitude = 40.7128, Longitude = -74.006, Timezone = new() { Double = -5 } });
168+
var chart = await roxy.Astrology.NatalChart.PostAsync(new() { Date = birthDate, Time = birthTime, Latitude = latitude, Longitude = longitude, Timezone = new() { String = timezone } });
163169
foreach (var p in chart!.Planets!)
164170
Console.WriteLine($"{p.Name}: {p.Sign} (house {p.House})");
165171
```
166172

167173
## Common tasks
168174

169-
Ordered by domain priority (Western, Vedic, Forecast, Human Design, Chinese Astrology, Feng Shui, Numerology, Tarot, Biorhythm, I Ching, Crystals, Dreams, Angel Numbers, Location).
175+
In the catalog order (Western astrology, Vedic astrology, forecast, Human Design, Chinese astrology, feng shui, Mesoamerican astrology, Vastu, numerology, Kabbalah, tarot, biorhythm, Ayurveda, I Ching, crystals, dreams, angel numbers, location, usage, languages). `Date, Time, Latitude, Longitude, Timezone` are the five values from the two-step pattern above; `Person1`, `Person2`, `PersonA`, `PersonB` and `BirthData` are nested bodies built from them.
170176

171177
| Task | Code |
172178
|------|------|
173-
| Daily horoscope | `roxy.Astrology.Horoscope["aries"].Daily.GetAsync()` |
179+
| Find city coordinates (do this first) | `roxy.Location.Search.GetAsync(c => c.QueryParameters.Q = "Berlin")` |
180+
| Daily horoscope | `roxy.Astrology.Horoscope[sign].Daily.GetAsync()` |
174181
| Natal chart (Western) | `roxy.Astrology.NatalChart.PostAsync(new() { Date, Time, Latitude, Longitude, Timezone })` |
175182
| Synastry | `roxy.Astrology.Synastry.PostAsync(new() { Person1, Person2 })` |
176183
| Compatibility score | `roxy.Astrology.CompatibilityScore.PostAsync(new() { Person1, Person2 })` |
177184
| Current moon phase | `roxy.Astrology.MoonPhase.Current.GetAsync()` |
185+
| Transits | `roxy.Astrology.Transits.PostAsync(new() { NatalChart })` |
178186
| Kundli (Vedic birth chart) | `roxy.VedicAstrology.BirthChart.PostAsync(new() { Date, Time, Latitude, Longitude, Timezone })` |
179187
| Panchang (detailed) | `roxy.VedicAstrology.Panchang.Detailed.PostAsync(new() { Date, Latitude, Longitude, Timezone })` |
188+
| Choghadiya | `roxy.VedicAstrology.Panchang.Choghadiya.PostAsync(new() { Date, Latitude, Longitude, Timezone })` |
180189
| Current dasha | `roxy.VedicAstrology.Dasha.Current.PostAsync(new() { Date, Time, Latitude, Longitude, Timezone })` |
181190
| Mangal Dosha | `roxy.VedicAstrology.Dosha.Manglik.PostAsync(new() { Date, Time, Latitude, Longitude, Timezone })` |
182191
| Guna Milan (matching) | `roxy.VedicAstrology.Compatibility.PostAsync(new() { Person1, Person2 })` |
183192
| Navamsa (D9) | `roxy.VedicAstrology.Navamsa.PostAsync(new() { Date, Time, Latitude, Longitude, Timezone })` |
184-
| KP ruling planets | `roxy.VedicAstrology.Kp.RulingPlanets.PostAsync(new() { Latitude, Longitude, Timezone, Datetime })` |
193+
| KP chart | `roxy.VedicAstrology.Kp.Chart.PostAsync(new() { Date, Time, Latitude, Longitude, Timezone })` |
194+
| KP ruling planets | `roxy.VedicAstrology.Kp.RulingPlanets.PostAsync(new() { Latitude, Longitude, Timezone })` |
185195
| Nakshatra detail | `roxy.VedicAstrology.Nakshatras["ashwini"].GetAsync()` |
196+
| Transit forecast | `roxy.Forecast.Transits.PostAsync(new() { BirthData, StartDate, EndDate })` |
197+
| Cross-domain timeline | `roxy.Forecast.Timeline.PostAsync(new() { BirthData, StartDate, EndDate })` |
198+
| Human Design bodygraph | `roxy.HumanDesign.Bodygraph.PostAsync(new() { Date, Time, Timezone })` |
199+
| Human Design connection | `roxy.HumanDesign.Connection.PostAsync(new() { PersonA, PersonB })` |
200+
| BaZi Four Pillars | `roxy.ChineseAstrology.Bazi.Chart.PostAsync(new() { Date, Time, Timezone })` |
201+
| Chinese zodiac animal | `roxy.ChineseAstrology.Zodiac.Sign.PostAsync(new() { Date })` |
202+
| Almanac day (Tong Shu) | `roxy.ChineseAstrology.Calendar.Day["2026-10-01"].GetAsync()` |
203+
| Kua number | `roxy.FengShui.Kua.PostAsync(new() { Date, Gender })` |
204+
| Flying star natal chart | `roxy.FengShui.FlyingStars.Natal.PostAsync(new() { Period, Facing })` |
205+
| Tzolkin day sign | `roxy.MesoamericanAstrology.Mayan.Tzolkin.PostAsync(new() { Date })` |
206+
| Full Maya chart | `roxy.MesoamericanAstrology.Mayan.Chart.PostAsync(new() { Date })` |
207+
| Vastu entrance | `roxy.Vastu.Entrance.PostAsync(new() { Plot, Facing, DoorPosition })` |
208+
| Vastu room compliance | `roxy.Vastu.Rooms.PostAsync(new() { Plot, Facing, Rooms })` |
186209
| Life path number | `roxy.Numerology.LifePath.PostAsync(new() { Year, Month, Day })` |
187210
| Full numerology chart | `roxy.Numerology.Chart.PostAsync(new() { FullName, Year, Month, Day })` |
188-
| Personal year | `roxy.Numerology.PersonalYear.PostAsync(new() { Month, Day, Year })` |
211+
| Personal year | `roxy.Numerology.PersonalYear.PostAsync(new() { Month, Day })` |
212+
| Gematria | `roxy.Kabbalah.Gematria.PostAsync(new() { Text })` |
213+
| Kabbalah birth profile | `roxy.Kabbalah.BirthProfile.PostAsync(new() { Date, Time, Timezone })` |
189214
| Daily tarot card | `roxy.Tarot.Daily.PostAsync(new() { Seed })` |
190215
| Three-card spread | `roxy.Tarot.Spreads.ThreeCard.PostAsync(new() { Question })` |
191216
| Celtic Cross | `roxy.Tarot.Spreads.CelticCross.PostAsync(new() { Question })` |
192217
| Yes / no tarot | `roxy.Tarot.YesNo.PostAsync(new() { Question })` |
193-
| Human Design bodygraph | `roxy.HumanDesign.Bodygraph.PostAsync(new() { Date, Time, Latitude, Longitude, Timezone })` |
194-
| Forecast timeline | `roxy.Forecast.Timeline.PostAsync(new() { BirthData, StartDate, EndDate })` |
195-
| Daily biorhythm | `roxy.Biorhythm.Daily.PostAsync(new() { Seed })` |
196-
| Cast I Ching reading | `roxy.Iching.Cast.GetAsync(c => c.QueryParameters.Seed = "user-42")` |
197-
| Crystal by zodiac | `roxy.Crystals.Zodiac["scorpio"].GetAsync()` |
198-
| Crystal by chakra | `roxy.Crystals.Chakra["Heart"].GetAsync()` |
199-
| Dream symbol lookup | `roxy.Dreams.Symbols["snake"].GetAsync()` |
218+
| Biorhythm reading | `roxy.Biorhythm.Reading.PostAsync(new() { BirthDate })` |
219+
| Daily biorhythm (seeded) | `roxy.Biorhythm.Daily.PostAsync(new() { Seed })` |
220+
| Biorhythm forecast | `roxy.Biorhythm.Forecast.PostAsync(new() { BirthDate })` |
221+
| Biorhythm compatibility | `roxy.Biorhythm.Compatibility.PostAsync(new() { Person1, Person2 })` |
222+
| Ayurvedic constitution | `roxy.Ayurveda.Constitution.PostAsync(new() { Date, Time, Latitude, Longitude, Timezone })` |
223+
| Dinacharya | `roxy.Ayurveda.Dinacharya.PostAsync(new() { Date, Latitude, Longitude, Timezone })` |
224+
| Daily hexagram | `roxy.Iching.Daily.PostAsync(new() { Seed })` |
225+
| Cast I Ching reading | `roxy.Iching.Cast.GetAsync()` |
226+
| Hexagram detail | `roxy.Iching.Hexagrams[1].GetAsync()` |
227+
| Crystal by zodiac | `roxy.Crystals.Zodiac[sign].GetAsync()` |
228+
| Crystal by chakra | `roxy.Crystals.Chakra[chakra].GetAsync()` |
229+
| Dream symbol lookup | `roxy.Dreams.Symbols["flying"].GetAsync()` |
200230
| Angel number meaning | `roxy.AngelNumbers.Numbers["1111"].GetAsync()` |
201-
| Find city coordinates | `roxy.Location.Search.GetAsync(c => c.QueryParameters.Q = "Berlin")` |
231+
| Universal number lookup | `roxy.AngelNumbers.Lookup.GetAsync(c => c.QueryParameters.Number = "1234")` |
202232
| Check API usage | `roxy.Usage.GetAsync()` |
233+
| List supported languages | `roxy.Languages.GetAsync()` |
203234

204235
## Field formats that trip agents
205236

@@ -217,20 +248,21 @@ Copy the format column exactly.
217248
| `Seed` | Any string (deterministic) | `"user-42"`, `"session-abc"` | numbers, objects |
218249
| `number` (angel numbers indexer) | String | `["1111"]`, `["777"]` | `[1111]` |
219250
| `Lang` (query) | Lowercase code | `c.QueryParameters.Lang = "hi"` | `"Hindi"`, `"HI"` |
251+
| Enum fields (`Gender`, `Facing`, `Unit`, room `Type`) | The generated enum, which lives in the namespace of its request body | `KuaPostRequestBody_gender.Female` after `using RoxyApi.FengShui.Kua;` | `"female"`, `Gender = "Female"` |
220252

221253
### Timezone cheat sheet (decimal offsets)
222254

223255
| Region | Decimal | Region | Decimal |
224256
|--------|---------|--------|---------|
225-
| UTC / London (winter) | `0` | Delhi / Kolkata (IST) | `5.5` |
257+
| UTC / London (winter) | `0` | Delhi (IST) | `5.5` |
226258
| Berlin / Paris | `1` (winter) / `2` (summer) | Kathmandu | `5.75` |
227259
| Istanbul / Moscow | `3` | Dhaka | `6` |
228260
| Dubai | `4` | Bangkok | `7` |
229261
| New York (EST / EDT) | `-5` / `-4` | Singapore / Beijing | `8` |
230262
| Chicago (CST / CDT) | `-6` / `-5` | Tokyo | `9` |
231263
| Los Angeles (PST / PDT) | `-8` / `-7` | Sydney | `10` / `11` (summer) |
232264

233-
DST matters for Western charts: use the summer offset if the birth date falls in a daylight-saving window, or pass the IANA name and let the server resolve it. Vedic endpoints default to IST (`5.5`), which is DST-free.
265+
DST matters. If the birth date falls inside a daylight-saving window, use the summer / DST offset, or pass the IANA string from the location lookup and let the server resolve it. India observes no DST, so a fixed `5.5` is always right there; anywhere else, a natal chart must carry the offset in force at the time of birth.
234266

235267
## Astrology domain gotchas
236268

@@ -257,10 +289,13 @@ Use the SDK for typed .NET apps. Use MCP for AI agents (Claude, Cursor, ChatGPT)
257289
## Gotchas
258290

259291
- **Geocode first.** Any chart, panchang, synastry, compatibility, or natal endpoint needs coordinates. Call `roxy.Location.Search` before the chart method.
260-
- **Path params are indexers, query params are a lambda.** `roxy.Astrology.Horoscope["aries"].Daily.GetAsync(c => c.QueryParameters.Date = new Date(2026, 4, 3))`.
261-
- **Do not guess method names.** Type `roxy.Domain.` and let IntelliSense show the fluent tree. It mirrors the URL path.
292+
- **Path params are indexers, query params are a lambda.** `roxy.Astrology.Horoscope["aries"].Daily.GetAsync(c => c.QueryParameters.Date = new Date(2026, 4, 3))`. An indexer is typed from the spec: a numeric path param takes a number (`Birthstone[1]`, `Hexagrams[1]`), a string one takes a string (`Numbers["1111"]`, `Calendar.Day["2026-10-01"]`).
293+
- **Do not guess method names.** Type `roxy.Domain.` and let IntelliSense show the fluent tree. It mirrors the URL path, not the `operationId`.
262294
- **Responses are nullable.** Use `result!.Field` or null checks; the success body is non-null only on a 2xx (errors throw).
263295
- **`Timezone` is a union wrapper, never a bare number.** Use `new() { Double = -5 }` or `new() { String = "America/New_York" }`.
296+
- **Switch on `e.Code`, not `e.Message`.** The message may change; the code is stable.
297+
- **List endpoints return a paginated envelope**, `Total`, `Limit`, `Offset` plus a named list (`Cities`, `Crystals`, `Hexagrams`, `Symbols`), never a bare list. Pass `c => c.QueryParameters.Limit = 64` to widen a page; `Iching.Hexagrams` defaults to 20 of 64.
298+
- **Enums live beside their request body.** `Gender`, `Facing`, `Unit` and room `Type` are generated enums in the namespace of the body that uses them (`using RoxyApi.FengShui.Kua;`, `using RoxyApi.Vastu.Rooms;`), so the same member name can exist in several namespaces; the one the body expects is the one to use.
264299
- **Do not expose API keys client-side.** Call Roxy from server, API, or backend code only.
265300

266301
## Dependencies

0 commit comments

Comments
 (0)