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.
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:
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 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_key identifies a valid scoped key.team_code identifies 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}/consentThere 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.
GET /get_supporters returns a complete snapshot rather than an incremental delta. The published response covers:
memberRef and contactId identifiers;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.
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:
memberRef is 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.
The mock and NGX consume @ramblers/sf-contract v1.0.2.
The package contains:
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
The operator console is separate from public API authentication.
An operator signs in, creates or selects a team and can then:
ExportAll.xlsx;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.
team_code.GET /get_supporters with the key and matching team code.The service remains deliberately small:
swagger-ui-express for interactive documentation;salesforce-mock.ngx-ramblers.org.uk hostname.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 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.
The mock follows the published document without answering questions that belong to Ramblers Head Office:
team_code values;/unsubscribe;memberRef is the definitive writeback identifier;membershipExpiry and membershipEndDate;canViewMemberDate;These are visible constraints rather than hidden assumptions.
Questions or suggested test scenarios can be raised through the mock repository or sent through NGX support.