# FlutterFlow

FlutterFlow compiles into an app your users hold, so the question is not which fields to fill in but where the key ends up. The request below was sent to production exactly as the call builds it; the FlutterFlow steps follow FlutterFlow's own documentation as of 2026-09-17.

Before you start, create a key as described in [A key for an automation](/en/integrations/#a-key-for-an-automation), scoped to `chart`.

<Aside type="caution" title="A key in an ordinary call ships with the app">
A call that is not private runs from the device, and its header travels inside the compiled iOS, Android and web bundle, where anyone can read it. Make the call **private**: FlutterFlow then routes it through a Firebase Cloud Function, and the key stays on the server. FlutterFlow's own check is to download the project code and search the frontend files for the key, which needs a paid plan.
</Aside>

## 1. Create the call

Open **API Calls**, press **+ Add**, choose **Create API Call** and fill it in:

- **API Call Name**: `Natal chart`.
- **Method Type**: `POST`.
- **URL**:

  ```
  https://api.astroway.info/v1/chart
  ```

- **Headers** tab, **+ Add Header**: one line, `X-Api-Key: ` followed by your key. A second line, `Content-Type: application/json`.
- **Variables** tab: five variables of type String, `date`, `time`, `timezone`, `latitude`, `longitude`, each with a default value from the table below.
- **Body** tab, dropdown set to **JSON**: paste the JSON below and drag each variable into place.

```json
{
  "date": "1990-05-15",
  "time": "14:30:00",
  "timezone": "Europe/Kyiv",
  "latitude": "50.45",
  "longitude": "30.52"
}
```

Latitude and longitude stay String variables on purpose: the API accepts `"50.45"` as a number, and a String keeps the drag-and-drop simple.

Press **Add Call**, then open **Response & Test**, press **Test API Call**, and read the answer in **Test Response**. `data.input.timezoneOffset` comes back as `4`, the offset Kyiv kept on that date.

## 2. Make it private

In the call's **Advanced Settings** turn on **Make Private**, press **Save**, then **Deploy APIs**. The call now runs in a Firebase Cloud Function, so the project needs Firebase connected and a Firebase plan that includes Cloud Functions.

<Aside type="caution" title="Private calls do not inherit group headers">
If you put the key on an **API Group** rather than on the call, FlutterFlow stops sending it the moment the call is made private: group headers are not inherited by private calls. Add `X-Api-Key` on the call itself, or the first private run comes back `401`.
</Aside>

Two more things the FlutterFlow docs are explicit about: a key passed in from the frontend, for example through a remote config, is still exposed even in a private call, and the safe shape is a header written into the call itself.

## 3. Read the answer

In **JSON Paths** press **+ Add JSON Path** and name each one:

| Name | JSON Path |
|---|---|
| `ascendant` | `$.data.houses.ascendant` |
| `sunLongitude` | `$.data.planets[0].longitude` |
| `moonLongitude` | `$.data.planets[1].longitude` |
| `offsetUsed` | `$.data.input.timezoneOffset` |

The sign is the longitude divided by 30, rounded down, as an index into the twelve names: for the example the Ascendant is `159.26`, which gives `5`, which is Virgo. A custom function of four lines does it, or a list of twelve strings and an index.

## A web build cannot call us from the browser

Measured on 2026-09-17 from a page on an unrelated origin: `POST /v1/chart` answers the preflight without an `access-control-allow-origin` header, and Chrome blocks it. Only `/v1/public/*` and `/v1/embed/*` answer a browser on someone else's domain.

FlutterFlow proxies API calls for you inside the builder, Run mode and Test mode, so a call that works there can still fail once the web app is deployed. Two routes out, and the first is the one we recommend:

- **Make the call private**, as above. It then runs in a Cloud Function rather than in the browser, which removes both the key problem and the CORS problem at once.
- **Put your own backend in front of us**, if you already run one. FlutterFlow's proxy settings, including the custom proxy URL, are documented for the builder and for Run and Test mode; the docs say nothing about a deployed web build, so do not count on them there.

A publishable `pk_` key does not solve this: it reaches only `/v1/public/*` and `/v1/embed/*`, and it is refused outright from iOS and Android builds, which send no web origin at all.

## Errors

- **`401`** on a private call: the key is on the group rather than on the call.
- **`400 INVALID_FIELD` with `timezone` in `details`**: the zone is empty, an abbreviation such as `EST`, or not a zone name.
- **`400` with `date` or `time` in `details`**: the format is not `YYYY-MM-DD` / `HH:MM:SS`.
- **`403 ENDPOINT_NOT_IN_SCOPE`**: the key's scope does not include `chart`.
- **`429 KEY_BUDGET_EXHAUSTED`**: the key reached its own budget; raise it in the dashboard.

<Aside type="note">
FlutterFlow's Free plan allows two API endpoints per project and no OpenAPI import, so a reader on Free adds this call by hand and has one slot left. The API does not geocode: coordinates come from your own inputs or from a geocoding service you hold a key for.
</Aside>
