# Calling outside services

> Let an app reach the hosts it lists, or the whole internet, and lend it a company credential it never sees.

By default an app reaches only the loopback: no DNS, no internet. To call an outside API, list the hosts in `sitesolide.json`, and the app's calls go through the egress proxy on your server.

```diagram
[Your app] HTTPS_PROXY set for it
-> CONNECT api.example.com
[Egress proxy] on your server
-> listed hosts, public addresses only
[Outside API] api.example.com
```

## Choose what the app reaches

| In `sitesolide.json` | The app reaches |
|---|---|
| Nothing | The loopback only. |
| `egress` | The hosts listed, through the egress proxy. |
| `"network": "outbound"` | The whole network. |
| `connectors` | A company credential, lent by the proxy. |

With a token, `egress` and `"network": "outbound"` need the *Use outbound network* permission.

## List the hosts it calls

In `sitesolide.json`:

```json
{
  "slug": "notes",
  "start": "/usr/local/bin/bun run server.ts",
  "egress": ["api.anthropic.com", "*.slack.com", "db.example.com:8443"]
}
```

- Write host names, never addresses.
- `*.example.com` matches every subdomain, never `example.com` itself.
- Without a port, an entry allows 443 and 80. With one, that port alone.

Deploy, and the next connection follows the new list. `deploy` refuses `egress` on a server without the proxy, which `sitesolide setup --minimal` leaves out.

The proxy learns which project calls from the kernel, which the app cannot fool. It refuses a host that resolves inside the server, to a private network or to the cloud's metadata service.

Bun's `fetch`, curl, Go and Python find the proxy on their own. Node's built-in `fetch` does not: see [which clients go through it](https://github.com/cthiriet/sitesolide/blob/main/egress/README.md#which-clients-go-through-it).

## Open the whole network

In `sitesolide.json`:

```json
"network": "outbound"
```

It cannot be combined with `egress`. Prefer `egress`, which names what the app calls.

## Lend a credential with a connector

A connector holds a company credential, such as a Slack token, that the app uses without seeing it. The owner defines and grants it; the project asks for it in its manifest.

1. In the dashboard, open **Connectors** and unlock.
2. Click *Add connector*, fill **Name** (`slack`), **Base address** (`https://slack.com/api`), **Header** and **Value**, and confirm.
3. Add `"connectors": ["slack"]` to `sitesolide.json`, and deploy.
4. Under **Grants**, click *Grant* for the project.
5. The app calls `$SITESOLIDE_CONNECTORS/slack/chat.postMessage` in plain HTTP. The proxy adds the header and forwards over HTTPS.

The credential is in neither the repository nor the app's environment.

## Limits

- An app can send whatever it likes to a host on its list. The list is the boundary.
- A connector's host must resolve to public addresses: a system on a private network cannot be one yet.

## Next steps

- [Secrets](secrets.md): keep API keys the app reads itself.
- [Teammates and tokens](tokens.md): the permission a token needs for outside hosts.
- [Security model](security.md): what each project can and cannot reach.

Full reference: https://github.com/cthiriet/sitesolide/blob/main/egress/README.md
