Embeddable Widgets
Create and manage embeddable widgets for your website. A widget is a ready-made UI component for one astrology feature: a natal chart form, a moon calendar, a daily horoscope picker. You configure it in the dashboard or through this API, and place it on any page with one script tag.
Two APIs, two keys
- The management API (
/api/widgets) creates and configures widgets. It uses your normal API key. - The widget API (
/api/widget-api) is what the SDK calls from the visitor's browser. It uses the widget's own key, which is safe to put in a page because it is scoped to that one widget.
Looking for the no-code guide? See Adding Widgets to Your Website.
Widget Types
Which widget types you can create depends on the modules on your organization. GET /api/widgets/options lists the ones available to you.
| Type | Description | Required modules |
|---|---|---|
natal | Birth data form with chart, positions and aspects | module:natal |
synastry | Two birth data forms, synastry chart and cross aspects | module:natal, module:synastry |
transit | Birth data plus a transit moment, bi-wheel chart | module:natal, module:transits |
composite | Two birth data forms, composite chart | module:natal, module:composite |
moonphase | Current moon phase with illumination | module:moon |
daily-horoscope | Sign picker with today's horoscope | module:daily-report |
numerology | Name and birth date form with core numbers | module:numerology |
compatibility | Two people, numerology compatibility score | module:numerology, module:compatibility |
moon-calendar | Monthly calendar with phases, moonrise and moonset | module:moon |
Widget Management
All management endpoints are JSON:API and use the widget resource type.
List Widgets
curl "https://api.astroapi.cloud/api/widgets" \
-H "X-Api-Key: your-api-key"Get Widget
curl "https://api.astroapi.cloud/api/widgets/wgt_abc123" \
-H "X-Api-Key: your-api-key"Create Widget
curl -X POST "https://api.astroapi.cloud/api/widgets" \
-H "X-Api-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"data": {
"type": "widget",
"attributes": {
"name": "My Natal Chart Widget",
"widgetType": "natal",
"allowedDomains": ["example.com", "www.example.com"],
"customization": {
"language": "en",
"layout": { "variant": "card" },
"colors": {
"primary": "#5b2d8e",
"background": "#ffffff",
"text": "#1a1a1a"
},
"widgetOptions": {
"showAspects": true,
"showPoints": true,
"showHouses": true,
"chartSize": "medium",
"theme": "auto"
}
}
}
}
}'The response of a create is the only time the full widget API key is returned (apiKey). Store it, or regenerate it later; every other response only carries apiKeyPrefix.
{
"data": {
"type": "widget",
"id": "wgt_abc123",
"attributes": {
"name": "My Natal Chart Widget",
"widgetType": "natal",
"customization": { "...": "as sent, merged with defaults when served" },
"allowedDomains": ["example.com", "www.example.com"],
"enabled": true,
"createdAt": "2026-06-15T12:00:00.000Z",
"updatedAt": "2026-06-15T12:00:00.000Z",
"apiKey": "wk_live_...",
"apiKeyPrefix": "wk_live_abc1"
},
"relationships": {
"organization": { "data": { "type": "organization", "id": "org_..." } }
}
}
}Update Widget
PATCH accepts any subset of name, enabled, allowedDomains and customization. Customization is replaced as a whole, so send the full object.
curl -X PATCH "https://api.astroapi.cloud/api/widgets/wgt_abc123" \
-H "X-Api-Key: your-api-key" \
-H "Content-Type: application/json" \
-d '{
"data": {
"type": "widget",
"id": "wgt_abc123",
"attributes": {
"name": "Updated Widget Name",
"customization": { "language": "nl" }
}
}
}'Delete Widget
curl -X DELETE "https://api.astroapi.cloud/api/widgets/wgt_abc123" \
-H "X-Api-Key: your-api-key"Regenerate the widget API key
curl -X POST "https://api.astroapi.cloud/api/widgets/wgt_abc123/regenerate-key" \
-H "X-Api-Key: your-api-key"Returns the widget with a fresh apiKey. Update the embed code on your site with the new key; the widget ID stays the same.
Available Widget Options
curl "https://api.astroapi.cloud/api/widgets/options" \
-H "X-Api-Key: your-api-key"{
"data": {
"type": "widget-options",
"id": "org_...",
"attributes": {
"plan": "Gold",
"organizationModules": ["module:natal", "module:moon"],
"availableWidgetTypes": ["natal", "moonphase", "moon-calendar"],
"features": {
"canRemoveBranding": false,
"canUseCustomLogo": false,
"canUseCustomCss": false,
"maxDomains": 5
},
"allWidgetTypes": [
{
"id": "natal",
"name": "Natal Chart",
"requiredModules": ["module:natal"],
"displayOptions": { "showChartSize": true, "showAspects": true, "showPoints": true }
}
]
}
}
}Plan Features
| Feature | Description |
|---|---|
canRemoveBranding | branding.showPoweredBy may be false |
canUseCustomLogo | branding.logoUrl and branding.companyName may be set |
canUseCustomCss | customCss is served to the widget |
maxDomains | Maximum number of allowedDomains per widget, or "unlimited" |
Customization Object
Every field is optional; what you leave out is filled from the defaults below when the widget is served. Colors are CSS color strings, sizes are numbers in pixels.
{
"colors": {
"primary": "#6366f1",
"secondary": "#8b5cf6",
"background": "#ffffff",
"surface": "#f8fafc",
"text": "#1e293b",
"textSecondary": "#64748b",
"border": "#e2e8f0",
"error": "#ef4444",
"success": "#22c55e",
"accent": "#f59e0b"
},
"fonts": {
"family": "Inter, system-ui, sans-serif",
"sizeBase": 16,
"sizeHeading": 24,
"sizeSmall": 12,
"weightNormal": 400,
"weightBold": 600
},
"borders": { "radius": 8, "width": 1, "style": "solid" },
"spacing": { "padding": 16, "margin": 16 },
"shadows": { "preset": "sm", "custom": null },
"layout": { "variant": "card" },
"interaction": {
"tooltipEnabled": true,
"animationsEnabled": true,
"clickThroughEnabled": false,
"clickThroughUrl": null
},
"chartSettings": {},
"labels": {},
"language": "en",
"branding": { "showPoweredBy": true, "logoUrl": null, "companyName": null },
"customCss": null,
"widgetOptions": {
"showAspects": true,
"showPoints": true,
"showHouses": true,
"chartSize": "medium",
"theme": "light"
},
"numerologyOptions": {
"showLifePath": true,
"showExpression": true,
"showSoulUrge": true,
"showPersonality": true,
"showBirthday": true,
"showPersonalCycles": true
},
"dailyHoroscopeOptions": { "autoRefresh": false },
"moonCalendarOptions": {
"showMoonrise": true,
"showMoonset": true,
"showIllumination": true,
"showPhaseEmoji": true,
"highlightFullMoon": true,
"highlightNewMoon": true
},
"compatibilityOptions": {
"showScore": true,
"showDescription": true,
"showLifePaths": true
}
}Customization Fields
| Field | Type | Description |
|---|---|---|
colors.* | string | Ten CSS colors, applied as CSS variables on the widget |
fonts.family | string | CSS font-family value |
fonts.sizeBase / sizeHeading / sizeSmall | number | Font sizes in pixels |
fonts.weightNormal / weightBold | number | Font weights |
borders.radius / width | number | Pixels; used by inputs, buttons and the card layout |
borders.style | string | solid, dashed, dotted or none |
spacing.padding / margin | number | Pixels; the card and compact layouts use padding |
shadows.preset | string | none, sm, md, lg or xl (card layout) |
shadows.custom | string | null | A CSS box-shadow that overrides the preset |
layout.variant | string | See Layout variants |
interaction.tooltipEnabled | boolean | Hover tooltips on planet rows, aspect rows and calendar days |
interaction.animationsEnabled | boolean | Entry animations; always off for visitors who prefer reduced motion |
interaction.clickThroughEnabled | boolean | Makes the rendered chart a link to clickThroughUrl |
interaction.clickThroughUrl | string | null | Opens in a new tab |
chartSettings | object | A partial chart theme merged over the default chart theme: colors per sign, point and aspect, stroke widths, showDegrees, showRetrograde and so on |
labels | object | Overrides for any label key; see Languages and labels |
language | string | One of the 13 supported language codes |
branding.showPoweredBy | boolean | Requires canRemoveBranding to set false |
branding.logoUrl / companyName | string | null | Require canUseCustomLogo |
customCss | string | null | Injected into the page for the widget; requires canUseCustomCss |
widgetOptions.showAspects / showPoints | boolean | Show the aspect and position tables under a chart |
widgetOptions.showHouses | boolean | Show house numbers on the chart |
widgetOptions.chartSize | string | number | small (300), medium (450), large (600) or a pixel width |
widgetOptions.theme | string | light, dark, cosmic, custom or auto |
numerologyOptions.* | boolean | Which numbers the numerology widget shows |
dailyHoroscopeOptions.autoRefresh | boolean | Reserved |
moonCalendarOptions.* | boolean | Which details a calendar day shows and which phases are highlighted |
compatibilityOptions.* | boolean | Score ring, description and life path numbers |
Layout variants
| Value | Description |
|---|---|
card | Bordered surface with the configured radius, padding and shadow (default) |
compact | Half the padding and slightly smaller type, for sidebars |
full | Edge to edge, vertical padding only |
minimal | No frame at all; inherits everything from the page |
Themes
light, dark and cosmic are fixed palettes for surfaces and borders. auto uses the light palette and switches to the dark one when the visitor's system prefers dark. custom sets nothing and relies on your colors. In every theme the ten colors you set win over the palette.
Languages and labels
The SDK ships labels for en, nl, de, fr, es, es-419, it, pt, pt-BR, tr, ru, ja and zh-CN. Region variants fall back to their base language for anything they do not override. labels overrides individual strings on top of the chosen language, for example:
{ "language": "nl", "labels": { "calculateButton": "Bereken mijn horoscoop" } }The language can also be set per page: data-lang="de" on the script tag, or ?lang=de in the page URL, both take precedence over the stored language.
Embedding a Widget
The SDK is served from https://widgets.astroapi.cloud/sdk.js. The dashboard's Embed tab produces both snippets below with your IDs filled in.
Auto-initialize
<script
src="https://widgets.astroapi.cloud/sdk.js"
data-widget-id="wgt_abc123"
data-api-key="your-widget-api-key"
data-api-url="https://api.astroapi.cloud"
></script>
<div id="astro-widget-wgt_abc123"></div>Optional attributes: data-container="#my-element" to render somewhere other than the default div, and data-lang="nl" to override the language.
Programmatic
<script src="https://widgets.astroapi.cloud/sdk.js"></script>
<div id="my-widget"></div>
<script>
AstroWidget.create({
widgetId: "wgt_abc123",
apiKey: "your-widget-api-key",
apiBaseUrl: "https://api.astroapi.cloud",
container: "#my-widget",
language: "nl",
defaultValues: {
dateTime: "1990-06-15T14:30:00",
latitude: 52.3676,
longitude: 4.9041,
timezone: "Europe/Amsterdam",
placeName: "Amsterdam"
},
onLoad: () => console.log("Widget loaded"),
onResult: (result) => console.log("Result", result),
onError: (err) => console.error(err)
}).then((widget) => {
// widget.type, widget.getResult(), widget.setBirthData(), widget.calculate(), widget.destroy()
});
</script>defaultValues.dateTime is interpreted as local time in timezone; the form shows it exactly as given.
Instance API
| Member | Description |
|---|---|
id, type | Widget ID and widget type |
getResult() | The latest result, whether the visitor calculated it or calculate() did |
setBirthData(data) | Birth data used by calculate() |
calculate() | Runs the calculation from script and shows the result. Supported for natal, transit (at the current moment), moonphase and moon-calendar (current month); the other types take their input from the visitor and reject with an error |
destroy() | Unmounts the widget |
onResult fires for every result the widget shows, for all widget types. AstroWidget.version reports the SDK build.
Domains
allowedDomains restricts where the widget API key works, checked against the Origin of the browser request. Subdomain wildcards (*.example.com) are supported and www. is treated as the bare domain. With an empty list the key works on any domain, so fill it in before you publish the embed code.
Widget API
These are the endpoints the SDK calls on behalf of a visitor. They are listed so you can build your own front end against a widget; the SDK is the reference client.
Authentication is the widget API key in X-Api-Key. The dashboard preview uses a session instead.
| Endpoint | Body | Widget type |
|---|---|---|
GET /api/widget-api/config/:widgetId | — | any; public, returns widgetType and the merged customization |
POST /api/widget-api/natal/:widgetId | { birthData } | natal |
POST /api/widget-api/synastry/:widgetId | { person1, person2 } | synastry |
POST /api/widget-api/transit/:widgetId | { birthData, transitDateTime, transitTimezone? } | transit |
POST /api/widget-api/composite/:widgetId | { person1, person2 } | composite |
POST /api/widget-api/moonphase/:widgetId | { date?, latitude? } | moonphase |
POST /api/widget-api/daily-horoscope/:widgetId | { zodiacSign, date? } | daily-horoscope |
POST /api/widget-api/numerology/:widgetId | { fullName, birthYear, birthMonth, birthDay } | numerology |
POST /api/widget-api/compatibility/:widgetId | { person1, person2 } (name and birth date parts) | compatibility |
POST /api/widget-api/moon-calendar/:widgetId | { year, month, latitude?, longitude?, timezone? } | moon-calendar |
GET /api/widget-api/geocoding/search/:widgetId?q=&limit=&lang= | — | any; place search for the birth data form |
birthData, person1 and person2 for the chart widgets are { dateTime, latitude, longitude, timezone, placeName? } with dateTime as local time (1990-06-15T14:30:00) in timezone. Calling an endpoint for a widget of another type returns 400; a disabled widget returns 403; a request from a domain outside allowedDomains returns 403 DOMAIN_NOT_ALLOWED.
Next Steps
- Adding Widgets to Your Website — step-by-step for WordPress, Wix, Squarespace, Shopify and Webflow
- Chart Rendering — the theme object that
chartSettingsaccepts - AI Chatbot — the chatbot has its own embeddable widget