21-Apr-2026 — Ramblers Team Emails Mock Server
Revised 23 July 2026. This article now describes the mock after its migration from the original NGX API proposal to the published Ramblers Team Emails 1.0.0 specification. The former Ticket #209 routes, bearer-token authentication and incremental response model are no longer part of the public service.
The Ramblers Team Emails mock server is a live development and test implementation of the API published by Ramblers Head Office. It gives NGX Ramblers and other consumers an isolated, repeatable endpoint for building and testing integrations without using real supporter data.
The service is intentionally more capable than SwaggerHub's generated example responses. Operators can create team-specific datasets, generate varied supporter fixtures, issue scoped API keys, import or export Insight Hub spreadsheets and inspect unsubscribe or bounce writebacks.
Start here
- Interactive Swagger documentation
- Operator console
- Raw OpenAPI document
- Ramblers Team Emails 1.0.0 on SwaggerHub
- Mock server source
- Shared contract source
- NGX implementation programme
Why the mock still matters
Ramblers Head Office owns the published external interface. The mock does not define a competing API and NGX does not treat it as the source of the specification.
Its purpose is to make the published interface practical to consume:
- Consumers can develop before production credentials or representative production data are available.
- Each operator owns isolated team datasets and API keys.
- Synthetic fixtures cover audience and identity combinations that are awkward to reproduce on demand.
- Runtime validation catches request or response drift early.
- Unsubscribe and bounce calls remain visible for inspection.
- The same scenarios can be repeated across NGX, other consumers and future Head Office acceptance testing.
This keeps the contract, mock and consumers separate while ensuring they implement the same interface.
flowchart LR
Published["Ramblers Team Emails 1.0.0<br/>SwaggerHub"]
Contract["Shared contract v1.0.2<br/>types + runtime validation"]
subgraph testService["Live mock service"]
API["Express API"]
Admin["Operator console"]
Atlas@{ icon: "ngx:mongodb", label: "MongoDB Atlas", pos: "b", h: 48 }
Admin --> Atlas
API --> Atlas
end
NGX@{ icon: "ngx:ramblers", label: "NGX Ramblers", pos: "b", h: 48 }
Other["Other API consumers"]
Published --> Contract
Contract --> API
Contract --> NGX
NGX --> API
Other --> API
style testService fill:#E8F5EE,stroke:#9BC8AB,stroke-width:2px,rx:12,ry:12,color:#404143
The current API
The mock exposes the three operations in Ramblers Team Emails 1.0.0:
| Method | Path | Purpose |
|---|---|---|
GET |
/get_supporters |
Return the current supporter snapshot for a team |
POST |
/unsubscribe |
Record an unsubscribe request for a supporter |
POST |
/bounced_email |
Record a hard or soft email bounce |
Every operation uses the published query credentials:
api_keyidentifies a valid scoped key.team_codeidentifies the team being accessed.
The key and team must match. A key issued for one team cannot read supporters or submit writebacks for another.
The retired routes from the original proposal deliberately return 404:
GET /api/groups/{groupCode}/membersPOST /api/members/{membershipNumber}/consent
There is no compatibility façade for those routes. A consumer using the old interface should fail clearly rather than appear to work against an obsolete contract.
Supporter snapshots
GET /get_supporters returns a complete snapshot rather than an incremental delta. The published response covers:
- members and affiliated members, including the published membership states;
- current volunteers and their role details;
- Wellbeing Walkers;
- supporters with or without a membership number;
- stable
memberRefandcontactIdidentifiers; - contact and membership information;
- email, post and phone consent;
- walk-programme, campaigning and survey preferences;
- permission flags controlling member, volunteer and Wellbeing Walker email audiences;
- permission to view supporter data.
The mock generates representative combinations of these states. This matters particularly for non-members, because membershipNo can be null while memberRef and contactId remain available.
Consumers must not infer a deletion, resignation or transfer merely because a supporter is missing from a later snapshot. The published API does not currently define the meaning of disappearance, so NGX retains the previous record for review.
Unsubscribe and bounce writebacks
The two write operations use memberRef and email address rather than the former membership-number path.
POST /bounced_email accepts the published Hard and Soft values. The mock records the team, supporter, bounce type, received time and outcome so duplicate or repeated provider events can be inspected.
POST /unsubscribe is also recorded, but the mock deliberately does not invent the resulting consent change. Ramblers Head Office still needs to confirm:
- which preference the operation changes;
- whether the effect applies only to the supplied team or across Ramblers;
- whether
memberRefis definitively the writeback identifier in every case.
Until those semantics are confirmed, an accepted mock unsubscribe means that the request was structurally valid and auditable, not that a locally invented consent rule has been applied.
Shared contract and drift detection
The mock and NGX consume @ramblers/sf-contract v1.0.2.
The package contains:
- TypeScript request, response and supporter types;
- Zod validators used at runtime;
- the resolved Ramblers Team Emails 1.0.0 OpenAPI definition;
- the generated OpenAPI artefacts used by the mock;
- error and status mappings;
- ESM and CommonJS entry points;
- a migration guide from the original #209 wire format.
The contract repository checks the live resolved SwaggerHub definition against its pinned copy. A material upstream change produces a reviewable failure rather than silently changing consumer behaviour. Formatting-only differences are normalised away.
flowchart LR
Swagger["SwaggerHub<br/>resolved OpenAPI"]
Pinned["Pinned upstream definition"]
Schemas["Types + Zod schemas"]
Mock["Mock build and tests"]
NGX["NGX build and tests"]
Swagger --> Drift{"Semantic drift check"}
Pinned --> Drift
Drift --> Schemas
Schemas --> Mock
Schemas --> NGX
Operator and team isolation
The operator console is separate from public API authentication.
An operator signs in, creates or selects a team and can then:
- import an Insight Hub
ExportAll.xlsx; - generate synthetic supporter fixtures;
- preview the team's current supporters;
- issue or revoke team-scoped API keys;
- inspect unsubscribe and bounce writebacks;
- clear and rebuild test data.
API keys are shown once and stored only as hashes plus non-secret prefixes. Every supporter, key and writeback record carries the owning team code, and all data access is filtered by it.
The root operator can administer the service. Ordinary operators only see teams they own.
Typical test flow
- Sign in to the operator console.
- Create or select a team using the intended
team_code. - Import Insight Hub data or generate synthetic supporters.
- Generate an API key for that team and copy it when shown.
- Open the Swagger UI.
- Call
GET /get_supporterswith the key and matching team code. - Exercise hard and soft bounce calls or an unsubscribe request.
- Return to the operator console and inspect the writeback history.
- Try the same key with a different team code to confirm isolation.
Infrastructure and deployment
The service remains deliberately small:
- Node.js and TypeScript;
- Express for the HTTP API;
- Mongoose and MongoDB Atlas for isolated test data;
- Zod and the shared contract for runtime validation;
swagger-ui-expressfor interactive documentation;- a lightweight operator interface compiled with Vite;
- Fly.io hosting behind the
salesforce-mock.ngx-ramblers.org.ukhostname.
Pushes to main run typechecking, linting, build and tests before deployment. The latest implementation includes route tests for valid and invalid credentials, cross-team attempts, published response shapes, hard and soft bounce values and rejection of the retired routes.
Insight Hub during transition
Insight Hub import and export remain useful test facilities because groups still depend on spreadsheets for supporter fields not included in API 1.0.0.
That compatibility should not be mistaken for the desired end state. The missing supporter-field set and the operational and GDPR implications of continuing to handle exports are tracked in NGX Ticket #334.
Known Phase One questions
The mock follows the published document without answering questions that belong to Ramblers Head Office:
- whether area codes are valid
team_codevalues; - whether area-sized responses will be paged;
- the exact scope and effect of
/unsubscribe; - whether
memberRefis the definitive writeback identifier; - the intended distinction between
membershipExpiryandmembershipEndDate; - the meaning of
canViewMemberDate; - how consumers should interpret a supporter disappearing from a snapshot.
These are visible constraints rather than hidden assumptions.
Current implementation tickets
- ramblers-salesforce-contract#2 — shared contract alignment, completed in v1.0.2.
- ramblers-salesforce-contract#3 — published-interface drift detection.
- ramblers-salesforce-mock#9 — the three Ramblers Team Emails operations.
- ramblers-salesforce-mock#10 — supporter fixtures and writeback auditing.
- ngx-ramblers#327 — ordered NGX adoption programme.
- ngx-ramblers#334 — deferred supporter-field parity and Insight Hub retirement.
References
- Ramblers Team Emails 1.0.0
- Live mock
- Interactive Swagger UI
- Operator console
- Raw OpenAPI JSON
- Mock repository
- Shared contract repository
- NGX Ramblers repository
Questions or suggested test scenarios can be raised through the mock repository or sent through NGX support.