Skip to content

Commit b686979

Browse files
committed
docs: server-side usage, drop publishable-key promise, add Human Design and Forecast
Rewrite getting-started and integration docs around server-side usage with a secret key, since browser-safe publishable keys are not shipped yet. Start with one component now mirrors the SDK quick start: one typed call, render the result. Remove every publishable-key instruction from the README, AGENTS, and examples; widgets auto-mount is labelled coming soon. The server-rendered section loads the bundle once. Add Human Design and Forecast to the most-used-components guide in canonical order, and rework the vanilla, vue, and WordPress examples to fetch server side and inline the response so no key ships to the browser.
1 parent 4acdce8 commit b686979

8 files changed

Lines changed: 415 additions & 389 deletions

File tree

AGENTS.md

Lines changed: 30 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,13 @@ const { data: chart } = await roxy.astrology.generateNatalChart({
120120

121121
Every chart endpoint accepts `timezone` as either a decimal-hour offset (`5.5` for IST, `-5` for EST) or an IANA name (`'Asia/Kolkata'`, `'America/New_York'`). The decimal form is what `/location/search` returns; the IANA form is correct over DST boundaries. Pick one and stay consistent in a single integration. Mixing them does not break the API but makes the bug surface area larger.
122122

123-
### 4. Secret key in the browser
123+
### 4. API key in the browser
124124

125-
There are two key classes. **Secret keys are unprefixed** and grant full access; they belong server-side only (Node, Bun, Hono, Next.js route handlers, Workers, Edge functions). **Publishable keys** are prefixed `pk_live_*` or `pk_test_*` and are safe in the browser; they are locked to an origin allowlist at the API gateway. For widgets, embeds, vanilla HTML, and `data-publishable-key` use the publishable key. For the typed SDK on a server, use the secret key.
125+
Keys are server side only. Call `createRoxy(process.env.ROXY_API_KEY!)` on your server (Node, Bun, Hono, Next.js route handlers, Workers, Edge functions), then send the response, not the key, to the component. Never ship the key in a client bundle. Browser-safe keys for direct client-side embedding are on the roadmap, not yet available.
126126

127127
```ts
128-
// Server (Next.js route handler, Workers, Bun): secret key
128+
// Server side only
129129
const roxy = createRoxy(process.env.ROXY_API_KEY!);
130-
131-
// Browser (widgets auto-mount): publishable key
132-
<div data-roxy-widget="natal-chart" data-publishable-key="pk_live_xxx" ...></div>
133130
```
134131

135132
### 5. Missing `'use client'` in Next.js App Router
@@ -194,49 +191,49 @@ import type { NatalChartResponse } from '@roxyapi/sdk';
194191

195192
### Pattern 1: vanilla HTML, no build step
196193

194+
Fetch on your server with the secret key, then inline the response into the component as a child `<script type="application/json" class="roxy-data">`. The component reads it on load. No key in the browser.
195+
197196
```html
198197
<script
199198
src="https://cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/roxy-ui.js"
200199
crossorigin="anonymous"
201200
></script>
202201

203-
<roxy-natal-chart id="chart"></roxy-natal-chart>
204-
205-
<script type="module">
206-
import { createRoxy } from 'https://cdn.jsdelivr.net/npm/@roxyapi/sdk@latest/dist/factory.js';
207-
const roxy = createRoxy('pk_live_xxx');
208-
const { data } = await roxy.astrology.generateNatalChart({
209-
body: { date: '1990-01-15', time: '14:30:00', latitude: 19.07, longitude: 72.88, timezone: 5.5 },
210-
});
211-
document.getElementById('chart').data = data;
212-
</script>
202+
<roxy-natal-chart>
203+
<script type="application/json" class="roxy-data">
204+
{ "planets": [ ... ], "houses": [ ... ], "aspects": [ ... ] }
205+
</script>
206+
</roxy-natal-chart>
213207
```
214208

215-
### Pattern 2: React, with the typed SDK
209+
Setting the JavaScript `data` property always wins over the inlined JSON, so the same element also drives dynamic pages.
210+
211+
### Pattern 2: React, interactive
212+
213+
`<RoxyLocationSearch>` runs in the browser. On select, call your own route, which holds the secret key, and set the returned data on the chart. The key never reaches the client.
216214

217215
```tsx
218216
'use client';
219217

220-
import { createRoxy } from '@roxyapi/sdk';
221218
import {
222219
RoxyNatalChart,
223220
RoxyLocationSearch,
224221
type RoxyNatalChartProps,
225222
} from '@roxyapi/ui-react';
226223
import { useState } from 'react';
227224

228-
const roxy = createRoxy(process.env.NEXT_PUBLIC_ROXY_API_KEY!);
229-
230225
export function BirthChartView() {
231226
const [chart, setChart] = useState<RoxyNatalChartProps['data']>(undefined);
232227

233228
const onLocationSelect = async (e: CustomEvent<{ latitude?: number; longitude?: number; timezone?: number | string }>) => {
234229
const { latitude, longitude, timezone } = e.detail;
235230
if (latitude == null || longitude == null) return;
236-
const { data } = await roxy.astrology.generateNatalChart({
237-
body: { date: '1990-01-15', time: '14:30:00', latitude, longitude, timezone },
231+
// Your route calls roxy.astrology.generateNatalChart with the secret key.
232+
const res = await fetch('/api/natal-chart', {
233+
method: 'POST',
234+
body: JSON.stringify({ date: '1990-01-15', time: '14:30:00', latitude, longitude, timezone }),
238235
});
239-
setChart(data);
236+
setChart(await res.json());
240237
};
241238

242239
return (
@@ -248,51 +245,33 @@ export function BirthChartView() {
248245
}
249246
```
250247

248+
For a static chart with no picker, fetch in a Server Component and pass `data` to a client component (Pattern 6).
249+
251250
### Pattern 3: schema-driven form
252251

253-
`<roxy-endpoint-form>` reads the OpenAPI spec and renders the inputs for any endpoint. Listen for the `roxy-submit` event with the validated payload.
252+
`<roxy-endpoint-form>` reads the OpenAPI spec and renders the inputs for any endpoint. On `roxy-submit`, POST the validated values to your own route, which calls the SDK with the secret key, then set the returned data on the target component.
254253

255254
```html
256255
<roxy-endpoint-form
257256
data-endpoint="vedic-astrology/birth-chart"
258257
method="POST"
259258
submit-label="Generate kundli"
260259
></roxy-endpoint-form>
260+
<roxy-vedic-kundli chart-style="south"></roxy-vedic-kundli>
261261

262262
<script type="module">
263-
import { createRoxy } from 'https://cdn.jsdelivr.net/npm/@roxyapi/sdk@latest/dist/factory.js';
264-
const roxy = createRoxy('pk_live_xxx');
265263
const form = document.querySelector('roxy-endpoint-form');
266264
form.addEventListener('roxy-submit', async (e) => {
267-
const { values } = e.detail;
268-
const { data: kundli } = await roxy.vedicAstrology.generateBirthChart({ body: values });
269-
document.querySelector('roxy-vedic-kundli').data = kundli;
265+
// Your route calls roxy.vedicAstrology.generateBirthChart with the secret key.
266+
const res = await fetch('/api/kundli', { method: 'POST', body: JSON.stringify(e.detail.values) });
267+
document.querySelector('roxy-vedic-kundli').data = await res.json();
270268
});
271269
</script>
272270
```
273271

274-
### Pattern 4: widgets auto-mount (no JavaScript wiring)
275-
276-
Use a publishable key (`pk_live_*` or `pk_test_*`) for client-side embeds. Get one at <https://roxyapi.com/account>. Publishable keys are origin-restricted at the API gateway. Register the customer domain (e.g. `https://customer.com`) when creating the key, and the gateway will reject requests from any other origin. Never use a secret key in client-side code (secret keys are unprefixed and live server-side only).
277-
278-
```html
279-
<script
280-
src="https://cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/widgets.js"
281-
defer
282-
></script>
283-
284-
<div
285-
data-roxy-widget="natal-chart"
286-
data-publishable-key="pk_live_xxx"
287-
data-date="1990-01-15"
288-
data-time="14:30:00"
289-
data-latitude="19.07"
290-
data-longitude="72.88"
291-
data-timezone="5.5"
292-
></div>
293-
```
272+
### Pattern 4: widgets auto-mount (coming soon)
294273

295-
The auto-mount script reads `data-*` attributes, calls the matching endpoint, and renders the matching component.
274+
A zero-wiring embed that reads `data-*` attributes and renders the matching component is on the roadmap. It needs browser-safe keys, which are not yet available. Until then, use Pattern 1 (inline JSON) for no-build pages.
296275

297276
### Pattern 5: MCP tool-call response
298277

@@ -396,7 +375,7 @@ Every visible aspect of the chart is driven by `--roxy-*` CSS custom properties
396375

397376
## Domain ordering
398377

399-
When listing domains in user-visible copy, use the canonical order: Western astrology, Vedic astrology, numerology, tarot, biorhythm, I Ching, crystals, dreams, angel numbers. Location is utility, not a selling domain.
378+
When listing domains in user-visible copy, use the canonical order: Western astrology, Vedic astrology, numerology, tarot, human design, forecast, biorhythm, I Ching, crystals, dreams, angel numbers. Location is utility, not a selling domain.
400379

401380
## What not to ship
402381

README.md

Lines changed: 69 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -221,42 +221,24 @@ Tables, cards, forms, and helper components in the [live demo](https://roxyapi.g
221221

222222
## Start with one component
223223

224-
Vanilla HTML. No build step. Replace `YOUR_API_KEY` with a publishable key from <https://roxyapi.com/account>.
224+
Fetch with the typed SDK, pass `data` to the component. No glue code.
225225

226-
```html
227-
<script
228-
src="https://cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/roxy-ui.js"
229-
crossorigin="anonymous"
230-
defer
231-
></script>
232-
<roxy-natal-chart id="chart"></roxy-natal-chart>
233-
<script type="module">
234-
import { createRoxy } from 'https://cdn.jsdelivr.net/npm/@roxyapi/sdk@latest/dist/factory.js';
235-
const roxy = createRoxy('YOUR_API_KEY');
236-
const { data } = await roxy.astrology.generateNatalChart({
237-
body: { date: '1990-01-15', time: '14:30:00', latitude: 19.07, longitude: 72.88, timezone: 5.5 },
238-
});
239-
document.getElementById('chart').data = data;
240-
</script>
241-
```
226+
```tsx
227+
import { createRoxy } from '@roxyapi/sdk';
228+
import { RoxyHoroscopeCard } from '@roxyapi/ui-react';
242229

243-
> **Unwrap `data` before passing to the component.** The SDK returns `{ data, error, request, response }`. Pass the envelope and the chart renders `[object Object]`. This is the most common integration bug.
230+
const roxy = createRoxy(process.env.ROXY_API_KEY!);
244231

245-
Want a Vedic kundli instead? Same shape, different SDK method:
232+
const { data } = await roxy.astrology.getDailyHoroscope({ path: { sign: 'aries' } });
246233

247-
```html
248-
<roxy-vedic-kundli id="kundli" chart-style="south"></roxy-vedic-kundli>
249-
<script type="module">
250-
import { createRoxy } from 'https://cdn.jsdelivr.net/npm/@roxyapi/sdk@latest/dist/factory.js';
251-
const roxy = createRoxy('YOUR_API_KEY');
252-
const { data } = await roxy.vedicAstrology.generateBirthChart({
253-
body: { date: '1990-01-15', time: '14:30:00', latitude: 19.07, longitude: 72.88, timezone: 5.5 },
254-
});
255-
document.getElementById('kundli').data = data;
256-
</script>
234+
return <RoxyHoroscopeCard data={data} />;
257235
```
258236

259-
In production, geocode the user's city with `<roxy-location-search>` (see [Quick start](#quick-start)) instead of hardcoding coordinates.
237+
Then expand into natal charts, kundli, dasha, tarot, and every other domain. The SDK returns `data`, the component renders it; the same pairing holds for all 32 components.
238+
239+
> **Pass `data`, not the envelope.** The SDK returns `{ data, error, request, response }`. Pass `data`, or the component renders `[object Object]`. This is the most common integration bug.
240+
241+
The key stays on your server. Vanilla HTML or a server-rendered page fetches the same way, then [inlines the JSON into the component](#server-rendered-no-javascript-wiring): no build step, no key in the browser. Try every component in the [live demo](https://roxyapi.github.io/ui/), each with Preview, Code, and shadcn tabs and a live color customizer.
260242

261243
## Install
262244

@@ -312,7 +294,12 @@ Always call `/location/search` first. Every chart endpoint expects latitude, lon
312294

313295
Server-rendered and cached pages (WordPress, JSX SSR, static HTML) cannot always run JavaScript to set the `data` property per element. Render the response into a child `<script type="application/json" class="roxy-data">` on the server instead. The component reads it on load. No per-element script, no API key in the browser.
314296

297+
Load the bundle once anywhere on the page. It registers every `roxy-*` element, so every component on the page renders from that single tag.
298+
315299
```html
300+
<!-- Once per page: defines every roxy-* element -->
301+
<script src="https://cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/roxy-ui.js" crossorigin="anonymous" defer></script>
302+
316303
<roxy-natal-chart>
317304
<script type="application/json" class="roxy-data">
318305
{ "planets": [ ... ], "houses": [ ... ], "aspects": [ ... ] }
@@ -464,7 +451,48 @@ const { data: cc } = await roxy.tarot.castCelticCross({
464451
<RoxyTarotSpread data={cc} />
465452
```
466453

467-
### 5. Biorhythm (daily, forecast)
454+
### 5. Human Design (bodygraph)
455+
456+
The breakout 2026 self-knowledge category, computed from the same ephemeris as Western astrology plus the I Ching gate wheel and chakra-style centers. Self-discovery apps, dating and compatibility products, and AI coaching bots ship the full bodygraph first. No coordinates needed; Human Design uses the birth instant, not the observer location.
457+
458+
```tsx
459+
import { RoxyBodygraph } from '@roxyapi/ui-react';
460+
461+
// Full bodygraph. The head term every Human Design app leads with ("human design chart").
462+
// Type, strategy, authority, profile, the nine centers, channels, and every gate
463+
// activation in one call. Pass the birth instant only, no latitude or longitude.
464+
const { data: bodygraph } = await roxy.humanDesign.generateBodygraph({
465+
body: { date: '1990-01-15', time: '14:30:00', timezone: 5.5 },
466+
});
467+
<RoxyBodygraph data={bodygraph} />
468+
```
469+
470+
### 6. Forecast (transits, cross-domain timeline)
471+
472+
The first cross-domain, stateless forecast in the catalog: one call merges Western transits, Vedic Vimshottari dasha boundaries, and biorhythm critical days into a single significance-scored, time-ordered timeline. Forecast feeds, transit alerts, and timing tools are the buyers. Acquire on the high-volume `astrology transits` search, convert on the cross-domain timeline no competitor ships. No coordinates needed.
473+
474+
```tsx
475+
import { RoxyForecastTimeline } from '@roxyapi/ui-react';
476+
477+
// Transit forecast. The demand leader. Western transit-to-natal aspects, sign
478+
// ingresses, and retrograde stations over the window.
479+
const { data: transits } = await roxy.forecast.forecastTransits({
480+
body: { birthData: { date: '1990-01-15', time: '14:30:00', timezone: 5.5 } },
481+
});
482+
<RoxyForecastTimeline data={transits} />
483+
484+
// Cross-domain timeline. The same window merged with Vedic dasha boundaries and
485+
// biorhythm critical days into one significance-scored timeline.
486+
const { data: timeline } = await roxy.forecast.generateTimeline({
487+
body: {
488+
birthData: { date: '1990-01-15', time: '14:30:00', timezone: 5.5 },
489+
domains: ['western', 'vedic', 'biorhythm'],
490+
},
491+
});
492+
<RoxyForecastTimeline data={timeline} />
493+
```
494+
495+
### 7. Biorhythm (daily, forecast)
468496

469497
Zero competition domain. Steady search volume with the top Google result being a static calculator page. Pure land-grab for wellness, productivity, sports, and couples apps.
470498

@@ -485,7 +513,7 @@ const { data: forecast } = await roxy.biorhythm.getForecast({
485513
<RoxyBiorhythmChart data={forecast} mode="forecast" />
486514
```
487515

488-
### 6. I Ching (cast a reading, hexagram lookup)
516+
### 8. I Ching (cast a reading, hexagram lookup)
489517

490518
Meditation apps, decision-making tools, and wisdom chatbots. `i ching API` and `hexagram API` are the keywords.
491519

@@ -505,12 +533,13 @@ const { data: random } = await roxy.iching.getRandomHexagram();
505533
506534
## API keys
507535

508-
Get keys at <https://roxyapi.com/account>.
536+
Get a key at <https://roxyapi.com/account>.
537+
538+
Today every key is a **secret key**: use it server side only (Node, Bun, Hono, Next.js route handlers, Workers). Never commit it, never ship it in a client bundle. Fetch on your server and send the rendered response, not the key, to the browser. The [Start with one component](#start-with-one-component) section and the [framework recipes](#most-used-components-per-domain) show the pattern.
509539

510-
- **Secret key** (server-side only). Use in Node, Bun, Hono, Next.js route handlers, Workers. Never commit, never ship in client bundles.
511-
- **Publishable key** (`pk_live_*` / `pk_test_*`). Safe in browsers, locked to the origins you register on the key. Use with the widgets auto-mount script for WordPress, Shopify, static HTML, embed scenarios. The API gateway rejects requests from any origin not on the allowlist.
540+
Set `ROXY_API_KEY` to your secret key in your server env for every SDK example on this page.
512541

513-
For the SDK examples on this page, set `ROXY_API_KEY` to a secret key in your server env. For the widgets auto-mount path (`data-publishable-key="pk_live_xxx"`), use a publishable key with your domain registered on it.
542+
Browser-safe keys for direct client-side embedding are on the roadmap, not yet available. Until they ship, keep the fetch on your server.
514543

515544
## Distribution
516545

@@ -520,7 +549,7 @@ For the SDK examples on this page, set `ROXY_API_KEY` to a secret key in your se
520549
| npm `@roxyapi/ui-react` | `npmjs.com/package/@roxyapi/ui-react` |
521550
| jsDelivr CDN (full bundle) | `cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/roxy-ui.js` |
522551
| jsDelivr CDN (per component) | `cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/components/{name}.js` |
523-
| Widgets auto-mount | `cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/widgets.js` |
552+
| Widgets auto-mount (with browser keys, coming soon) | `cdn.jsdelivr.net/npm/@roxyapi/ui@latest/dist/cdn/widgets.js` |
524553
| shadcn registry | `npx shadcn@latest add https://cdn.jsdelivr.net/gh/RoxyAPI/ui@latest/registry/{name}.json` |
525554

526555
## Components
@@ -770,7 +799,7 @@ Components ship in Shadow DOM for style isolation; Tailwind utilities are scoped
770799
<details>
771800
<summary><strong>What is the security model for API keys?</strong></summary>
772801

773-
Two key classes. Secret keys (unprefixed) live server-side only and grant full access. Publishable keys (`pk_live_*` / `pk_test_*`) are browser-safe and locked to an origin allowlist registered on the key. The API gateway rejects requests from any other origin and counts the failed attempt against the rate limit, so a stolen key cannot be brute-fired from elsewhere.
802+
Today keys are secret keys: they live server side only and grant full access, so never ship one in a client bundle. Fetch on your server and pass the rendered response, not the key, to the browser. Browser-safe keys with an origin allowlist for direct client-side embedding are on the roadmap and not yet available.
774803

775804
For CSP, allow `script-src https://cdn.jsdelivr.net` if loading the bundle from the CDN. Subresource Integrity hashes are available via the jsDelivr SRI API for any pinned version.
776805
</details>
@@ -781,11 +810,11 @@ For CSP, allow `script-src https://cdn.jsdelivr.net` if loading the bundle from
781810
Semver. Pre-1.0, minor bumps may include breaking changes (we will note them in the changelog). Patch bumps are always backwards-compatible. Pin a concrete version in production code:
782811

783812
```bash
784-
npm install @roxyapi/ui@0.1.x
813+
npm install @roxyapi/ui@0.8.x
785814
```
786815

787816
```html
788-
<script src="https://cdn.jsdelivr.net/npm/@roxyapi/ui@0.1.5/dist/cdn/roxy-ui.js"></script>
817+
<script src="https://cdn.jsdelivr.net/npm/@roxyapi/ui@0.8.0/dist/cdn/roxy-ui.js"></script>
789818
```
790819

791820
The `@latest` URL on this page is for paste-friendly marketing; production code should pin.

0 commit comments

Comments
 (0)