# Public ports and HTTPS endpoints
An **endpoint** is how the outside world reaches your Workload. There are two kinds, and you pick by what you run.

| | `https` | `port` |
|---|---|---|
| For | a website or an API (WebSockets included) | anything else: a game server, a database, a custom protocol |
| Address | a free platform host, plus your own domains | a public IP address and a public port Zaroz assigns |
| Protocol | TCP carrying HTTP; TLS is handled for you | `tcp`, `udp`, or `tcp_udp` on one number |
| Cost | free | billed by the hour it is held (see [Billing](/units/billing)) |

## HTTPS endpoints

An HTTPS endpoint publishes one container port. Your app serves plain HTTP on that port, and Zaroz terminates TLS with an automatic certificate.

- The free host looks like `<label>.zone.<zone>.zaroz.cloud`. You may choose the `label`.
- You can attach your own domains. Each must be a domain your organization has verified, or a subdomain of one. A domain that later loses verification stops being served.
- The request is spread across all of your ready units.
- It is all or nothing: if one domain is refused, nothing opens.

## Public ports

A public port maps one port **inside** your container (`internal_port`) to a public address and port that Zaroz assigns. The assigned address and number come back in the response.

- `tcp_udp` is one endpoint and one price, carrying both protocols over one public number.
- A public port goes to **one unit**, not to all of them. It is a direct line to a single pod. If you run several units and each needs its own public address, each one gets its own.
- Closing a port stops its billing from that moment. Nothing was prepaid, so there is nothing to refund.
- A closed port stays in the list, with its last address, so a month's invoice can be read against it.

### Free ports and extra ports

A plan can include some free port slots. A Workload's plan includes none, so every raw port is billed. HTTPS endpoints are always free.

## Pending ports

A port you ask for when buying is `pending` until the service is running. Nothing is billed while it is pending, and `pending_reason` says why it has not opened. You can withdraw a pending request the same way you close an open port.

## Refusals

When a request is refused, the `details` field starts with a reason code before the colon:

| code | meaning |
|---|---|
| `not_ready` | the service is not running yet |
| `port_limit` | all the plan's ports are in use |
| `port_in_use` | that container port is already open with that protocol, or already has an HTTPS endpoint |
| `no_address_available`, `no_port_available` | nothing free right now; try again later |
| `internal_port_out_of_range` | the port is not between 1 and 65535 |
| `protocol_required`, `unknown_protocol` | a `port` needs `tcp`, `udp` or `tcp_udp` |
| `invalid_host_label`, `host_taken`, `https_limit` | the HTTPS label or count is not allowed |
| `invalid_domain`, `platform_domain`, `domain_taken`, `domain_not_verified`, `domain_limit` | a custom domain was not accepted |

The step-by-step is in [Add a public port](/guides/containers-public-port).

:::note{title="API status"}
The endpoint routes are used by the console and are tagged console-only in the API reference. They accept your session token or a personal access token, and refuse application tokens.
:::
