# Hosted services

> Six first-party services behind one route shape: web search, page scraping, geolocation, email, image generation, and chat completion. Billed to the workspace.

Source: https://docs.generalinput.com/api/platform



Hosted services are the platform's own APIs, the same ones agents reach from `bash` through `$PLATFORM_BASE_URL`. Over `/v1` they sit behind one route per service, forward the body unchanged, and bill the workspace.

<Access scope="platform:use" />

```
POST /v1/platform/<service>
```

| Service                                            | Does                                                                |
| -------------------------------------------------- | ------------------------------------------------------------------- |
| [`search-internet`](/api/platform/search-internet) | Web and image search with ranked results and optional page content. |
| [`proxy-scrape`](/api/platform/proxy-scrape)       | Fetch a page through a proxy, with JS rendering and anti-bot tiers. |
| [`geolocation`](/api/platform/geolocation)         | Geocode, reverse geocode, directions, distance matrix, and places.  |
| [`send-email`](/api/platform/send-email)           | Send an HTML email with attachments from the platform address.      |
| [`generate-image`](/api/platform/generate-image)   | Generate an image from a prompt, returned as base64.                |
| [`chat-completion`](/api/platform/chat-completion) | An OpenAI-style completion with selectable intelligence levels.     |

Any other service name is a `404`. There is one route, `POST /v1/platform/:service`, checked against a closed allowlist, so an unknown name never reaches anything.

## Billing and balance [#billing-and-balance]

Every call runs the balance guard first. A workspace with no credits gets `402` and nothing is forwarded. Usage is attributed to the workspace as external API usage; the workspace's credits page shows it under the member the key acts as.

## Errors [#errors]

The service's own status and body pass through unchanged (a `400` from the service reads as a `400` here, with its message). On top of that:

| Status | When                                                                                                                                            |
| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `402`  | The workspace has no balance.                                                                                                                   |
| `404`  | Unknown service name.                                                                                                                           |
| `500`  | Some services validate their body internally and surface a rejected request as a `500` rather than a `400`. Geolocation and send-email both do. |
| `502`  | The service could not be reached.                                                                                                               |

## Calling from a workflow instead [#calling-from-a-workflow-instead]

Inside a code workflow or an app handler, declare the service as a credential slot and read `getCredential(inputKey)`, which is `{ apiKey, baseUrl }`. Then call `${baseUrl}/<service>` with the same body documented here. The `/v1/platform` prefix is for keyed callers outside the platform.
