---
id: w3/m7/t002
title: REST GET /v1/services/{id}/events (Render envelope) + GraphQL serviceEvents
worker: worker3
status: todo
estimate: 30m
depends_on: [w3/m7/t001]
---

## Objective

The two primary adapters over the t001 view: REST `GET /v1/services/{id}/events` matching Render's OpenAPI (list envelope, cursor param/response, `limit` semantics — verify field-by-field before coding; `/v1/apps` alias included) and a GraphQL `serviceEvents(serviceId, …)` query for the future dashboard tab, in the existing per-feature fragment style. Authorize-gated like every verb.

## Context

- Fragments: `lego/backend/internal/events/{rest,graphql}.go`, composed in `internal/api/server.go`.
- Time-window params: honor `BEX_MAX_QUERY_HOURS` if the endpoint takes a range (match how logs/metrics enforce it — check the spec first for what Render's events endpoint actually accepts).

## Steps

1. Extract Render's events endpoint shapes from the spec; record honored/omitted fields.
2. REST + GraphQL fragments over the one service method; error mapping (404 unknown service, 403, store-less 503).
3. docs/ADR006-bex-api.md rows (REST table + GraphQL section).

## Files

- `lego/backend/internal/events/{service,rest,graphql}.go`
- `docs/ADR006-bex-api.md`

## Acceptance criteria

- [ ] REST shapes match the spec for every served field; both surfaces return identical event data; store-less mode 503s.

## Out of scope

- MCP (t003); SSE/live event streaming (Render's endpoint is poll-based; note if the spec says otherwise).
