---
title: "Where this project's devices send UDP datagrams, and how one is laid out (any member)"
method: GET
path: "/v1/projects/{project_id}/udp/endpoint"
tags: ["udp"]
---

# Where this project's devices send UDP datagrams, and how one is laid out (any member)

`GET /v1/projects/{project_id}/udp/endpoint`

## Request

- Base URL: `https://api.wavehouse.cloud`
- URL: `https://api.wavehouse.cloud/v1/projects/{project_id}/udp/endpoint`
- Auth: one of:
  - API key in cookie `whc_session`
  - HTTP bearer
  - API key in header `X-API-Key`

The static anycast `addresses` and port to send to — these never change, so a device hard-codes one. `hostname` is published too when this deployment has one configured, but it is optional and DNS-only: devices that cannot resolve DNS (most hardware senders) use `addresses` directly. A datagram is `device_id (8) ‖ nonce (nonce_len) ‖ payload ‖ tag (tag_len)` and carries NO version, length or delimiter: the widths come from the device's own row, which is why they are published here. The ACK is `nonce ‖ status (1) ‖ tag`, where status is 0 stored, 1 throttled, 2 disabled. `provisioned` is false where no listener is configured; the suite table is published either way so a device can be prepared first. `rejects_retention` is how long a parked datagram stays readable before the prune pass removes it.

## Path parameters

- `project_id` string, required

## Response `200`

OK

- UDPEndpointView
  - `addresses` string[], required: the canonical static endpoint: anycast addresses, IPv4 and IPv6, that never change — hard-code one
  - `device_id_len` integer, required: leading device-id bytes; the nonce starts here and the payload at device_id_len + nonce_len
  - `hostname` string: an optional DNS name for this deployment, when configured; addresses are the endpoint, not a fallback
  - `port` integer, required
  - `provisioned` boolean, required: false when this deployment has no UDP listener; the suite table is still published
  - `rejects_retention` UDPRejectsRetentionView, required
    - `acked_days` integer, required: days an acknowledged reject is kept
    - `max_per_project` integer, required: oldest rejects beyond this count are pruned regardless of age
    - `unacked_days` integer, required: days an unacknowledged reject is kept
  - `suites` UDPSuiteLayoutView[], required
    - `key_len` integer, required: bytes of raw key material the create response returns
    - `nonce_choices` integer[], required: the nonce widths a device row may take when the suite does not fix one
    - `nonce_len` integer, required: the cipher's own nonce size; 0 means the device row chooses one of nonce_choices
    - `sealed` boolean, required: the payload is encrypted, not only authenticated
    - `suite` string, required
    - `tag_len` integer, required: trailing MAC or AEAD tag bytes; 0 for the unauthenticated suite

## Other responses

- `429`: Rate limited, per client IP, API key or org; a client IP is also refused on every route for a while after repeated authentication failures. A limited operation carries RateLimit-Policy and RateLimit on every response; wait Retry-After seconds before retrying.
- `default`: Error

---

[API](https://skmtc.dev/wavehouse/apis/wavehouse-cloud-api.md) · [All operations](https://skmtc.dev/wavehouse/apis/wavehouse-cloud-api/llms.txt) · [OpenAPI document](https://skmtc.dev/wavehouse/apis/wavehouse-cloud-api/revisions/adea029bf505?raw)
