You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -88,7 +88,7 @@ These parameters are supported across most GET list endpoints:
88
88
|-----------|------|-------------|
89
89
|`limit`| integer (0-100) | Results per page (default: 100) |
90
90
|`offset`| integer | Pagination offset |
91
-
|`sort`| string | Sort field (prefix `-` for descending, e.g. `-startDate`) |
91
+
|`sort`| string | Sort field (prefix `-` for descending, e.g. `-startDate`). **Append `,id` for stable pagination** (e.g. `-updatedAt,id`).|
92
92
|`fields`| string | Comma-separated field list to restrict response |
93
93
|`search`| string | Free text search |
94
94
@@ -106,7 +106,7 @@ These parameters are supported across most GET list endpoints:
106
106
|-----------|------|-------------|
107
107
|`membership`| string | Filter by membership type ID |
108
108
|`group`| string | Filter by group ID |
109
-
|`updatedAt`| ISO 8601 | Filter by last update date |
109
+
|`updatedAt`| ISO 8601 | Filter members updated since this date (recommended for incremental sync)|
110
110
111
111
### Event Attendee Parameters
112
112
@@ -132,7 +132,7 @@ These parameters are supported across most GET list endpoints:
132
132
|`fromDate`| ISO 8601 |**Required** — start date for log range |
133
133
|`toDate`| ISO 8601 |**Required** — end date for log range |
134
134
135
-
> **Note:** The spec says `fromDate`/`toDate` are optional for checkInLog and emailLog, but the API returns 422 without them.
135
+
> **Note:** The spec says `fromDate`/`toDate` are optional for checkInLog and emailLog, but the API returns 422 without them. Hello Club have confirmed this is intentional (the spec is outdated). Same behaviour in V2.
Copy file name to clipboardExpand all lines: docs/gotchas.md
+28-11Lines changed: 28 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,10 +1,10 @@
1
1
# Gotchas & Known Issues
2
2
3
-
Common pitfalls when working with the Hello Club API, discovered through live testing.
3
+
Common pitfalls when working with the Hello Club API, discovered through live testing. Items marked **Verified** have been confirmed against the live API and corroborated by Hello Club support (Mar 2026).
4
4
5
5
## Removed Endpoint: `/event/upcoming`
6
6
7
-
`GET /event/upcoming` returns `400 BadRequestError: "Invalid request"` for **all parameter combinations**. Hello Club have confirmed this is not a bug — the endpoint has been removed, though it remains in the outdated OpenAPI spec. The same behaviour applies in V2.
7
+
**Verified.**`GET /event/upcoming` returns `400 BadRequestError: "Invalid request"` for all parameter combinations. Hello Club have confirmed this is not a bug — the endpoint has been removed, though it remains in the outdated OpenAPI spec. The same behaviour applies in V2.
8
8
9
9
**Workaround:** Use `GET /event` with `fromDate` and `toDate`:
The spec says `fromDate`/`toDate` are optional for these endpoints, but the API returns **422** without them. Hello Club have confirmed this is intentional — the spec is outdated, not the API. The same behaviour applies in V2.
26
+
**Verified.**The spec says `fromDate`/`toDate` are optional for these endpoints, but the API returns **422** (`ValidationError: "query.fromDate" is required`) without them. Hello Club have confirmed this is intentional — the spec is outdated, not the API. The same behaviour applies in V2.
27
27
28
28
-`GET /checkInLog` — returns 422 without dates
29
29
-`GET /emailLog` — returns 422 without dates
@@ -161,20 +161,31 @@ Always check for both `null` and empty values when parsing.
161
161
162
162
## Unstable Pagination with Non-Default Sort Orders
163
163
164
-
**Severity: High** — causes silent data loss when paginating through members.
164
+
**Verified. Fix confirmed.**
165
165
166
166
Sorting `GET /member` by anything other than the default (`-lastOnline`) produces **duplicate records** across pages, causing other members to be silently skipped. The offset-based pagination uses an unstable sort when records share the same sort value, so the same member can appear at different offsets on subsequent pages.
167
167
168
168
**Root cause (confirmed by Hello Club, Mar 2026):** The sort is unstable when multiple records share the same value for the sort field. To ensure stable sorting, append `,id` to your sort specifier (e.g. `sort=-updatedAt,id`). Hello Club may change the API to do this automatically in future.
169
169
170
-
### Test Results (Mar 2026, 2,143 total members)
170
+
### Test Results
171
+
172
+
**Original test (Mar 2026, full dataset — 2,143 total members):**
171
173
172
174
| Sort | Records Returned | Unique Members | Duplicates | Missing Members |
The `,id` tiebreaker completely eliminates the pagination bug.
188
+
178
189
### How to Reproduce
179
190
180
191
Fetch page 1 and page 2 with `sort=-updatedAt` and compare member IDs:
@@ -201,20 +212,24 @@ Any code that paginates through all members using `sort=-updatedAt` (e.g., for i
201
212
2. Process ~33% of members multiple times
202
213
3. Return a "complete" result set that is actually incomplete
203
214
204
-
### Workaround
215
+
### Fix: Append `,id` to Sort
205
216
206
-
**Fix (confirmed by Hello Club, Mar 2026):** Append `,id` to your sort to make pagination stable:
217
+
**Verified fix (confirmed by Hello Club, Mar 2026).** Append `,id` to any sort specifier to make pagination stable:
207
218
208
219
```python
209
-
# Stable sort — no duplicates or missing records
220
+
# Stable sort — 0 duplicates, 0 missing records (verified)
210
221
page = client.get("/member", params={
211
222
"limit": 100,
212
223
"offset": 0,
213
224
"sort": "-updatedAt,id", # id tiebreaker ensures stable ordering
214
225
})
215
226
```
216
227
217
-
**For incremental sync**, Hello Club also recommends filtering by `updatedAt` instead of sorting by it:
228
+
This works with any sort field, not just `updatedAt`. Always append `,id` when paginating with non-default sort orders.
229
+
230
+
### Alternative: Filter by `updatedAt`
231
+
232
+
**Verified.** For incremental sync, Hello Club recommends filtering by `updatedAt` instead of sorting by it. Tested with 1,381 members matching a 7-day window — all returned members had correct `updatedAt` dates:
218
233
219
234
```python
220
235
# Fetch only members updated since your last sync
@@ -234,7 +249,9 @@ while True:
234
249
offset +=100
235
250
```
236
251
237
-
**For full dataset fetches**, use the default sort (`-lastOnline`) and deduplicate by member ID:
252
+
### Fallback: Default Sort + Dedup
253
+
254
+
For full dataset fetches, use the default sort (`-lastOnline`) and deduplicate by member ID:
238
255
239
256
```python
240
257
members = {}
@@ -250,4 +267,4 @@ while True:
250
267
251
268
> **Note:** Even the default sort has ~28 duplicates out of 2,143 (1.3%), likely from members coming online during the paginated fetch. Always deduplicate by ID.
252
269
253
-
> **Tested:** Mar 2026 against a club with 2,143 members. Test script: [`scripts/test_api_sort_bug.py`](https://github.com/ispyisail/hc-group-fixer/blob/master/scripts/test_api_sort_bug.py)
270
+
> **Tested:** Mar 2026 against a club with 2,143 members. Verification script: [`scripts/verify_fixes.py`](scripts/verify_fixes.py). Original test: [`scripts/test_api_sort_bug.py`](https://github.com/ispyisail/hc-group-fixer/blob/master/scripts/test_api_sort_bug.py)
0 commit comments