Skip to content

Commit e7ffc35

Browse files
fix: Amplitude list creation response shape (#8402)
Co-authored-by: flagsmith-engineering[bot] <flagsmith-engineering[bot]@users.noreply.github.com>
1 parent 250aff3 commit e7ffc35

4 files changed

Lines changed: 35 additions & 12 deletions

File tree

api/cohorts/sync_views.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@
2222
)
2323

2424
_LIST_RESPONSE = inline_serializer(
25-
"AmplitudeListResponse", {"listId": serializers.UUIDField()}
25+
"AmplitudeListResponse",
26+
{
27+
"list_id": serializers.UUIDField(),
28+
"response": inline_serializer(
29+
"AmplitudeListResponseEnvelope", {"list_id": serializers.UUIDField()}
30+
),
31+
},
2632
)
2733

2834
_MIXPANEL_RESPONSE = inline_serializer(
@@ -73,10 +79,13 @@ def create(self, request: Request) -> Response:
7379
name=serializer.validated_data["name"],
7480
source_type=CohortSourceType.AMPLITUDE,
7581
)
76-
# Amplitude's production sync worker reads the list ID from its
77-
# documented default key, camelCase "listId", ignoring the response
78-
# path configured in the Integration Portal.
79-
return Response({"listId": str(cohort.uuid)})
82+
# Two different Amplitude systems read this response, and they look
83+
# for the list ID in different places: the real cohort sync reads
84+
# body["response"]["list_id"], the portal's Testing tab reads
85+
# body["list_id"]. Send both so neither breaks. Verified on
86+
# staging, 2026-08-31.
87+
list_id = str(cohort.uuid)
88+
return Response({"list_id": list_id, "response": {"list_id": list_id}})
8089

8190
@action(detail=True, methods=["POST"])
8291
def add(self, request: Request, pk: str) -> Response:

api/tests/unit/cohorts/test_sync_views.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ def test_amplitude_create_list__valid_key__creates_amplitude_cohort(
5050

5151
# Then
5252
assert response.status_code == status.HTTP_200_OK
53-
cohort = Cohort.objects.get(uuid=response.json()["listId"])
53+
cohort = Cohort.objects.get(uuid=response.json()["list_id"])
54+
# Amplitude's production worker reads the nested copy, its Testing tab
55+
# the flat one.
56+
assert response.json()["response"]["list_id"] == response.json()["list_id"]
5457
assert cohort.environment == key.environment
5558
assert cohort.source_type == CohortSourceType.AMPLITUDE
5659
assert cohort.segment.name == "[Amplitude] Beta users: 1234"
@@ -74,7 +77,7 @@ def test_amplitude_create_list__postgres_environment__creates_cohort(
7477

7578
# Then
7679
assert response.status_code == status.HTTP_200_OK
77-
cohort = Cohort.objects.get(uuid=response.json()["listId"])
80+
cohort = Cohort.objects.get(uuid=response.json()["list_id"])
7881
assert cohort.environment == environment
7982

8083

@@ -350,7 +353,7 @@ def test_amplitude_create_list__valid_key__audits_and_queues_environment_update(
350353
# Then - the audit record carries no user, names the source, and is the
351354
# hook that rebuilds the environment document.
352355
assert response.status_code == status.HTTP_200_OK
353-
cohort = Cohort.objects.get(uuid=response.json()["listId"])
356+
cohort = Cohort.objects.get(uuid=response.json()["list_id"])
354357
audit_log = AuditLog.objects.get(related_object_id=cohort.segment_id)
355358
assert audit_log.author is None
356359
assert audit_log.master_api_key is None
@@ -377,7 +380,7 @@ def test_amplitude_create_list__valid_key__history_records_no_user(
377380
# Then - a machine caller leaves no user on historical records; stamping
378381
# one would fail, since the sync key is not a Flagsmith user.
379382
assert response.status_code == status.HTTP_200_OK
380-
cohort = Cohort.objects.get(uuid=response.json()["listId"])
383+
cohort = Cohort.objects.get(uuid=response.json()["list_id"])
381384
history_record = cohort.segment.history.get()
382385
assert history_record.history_user is None
383386
assert history_record.master_api_key is None

docs/docs/deployment-self-hosting/observability/_events-catalogue.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ Attributes:
166166
### `cohorts.sync_webhook.rejected`
167167

168168
Logged at `warning` from:
169-
- `api/cohorts/sync_views.py:217`
169+
- `api/cohorts/sync_views.py:226`
170170

171171
Attributes:
172172
- `action`

openapi.yaml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18943,11 +18943,22 @@ components:
1894318943
AmplitudeListResponse:
1894418944
type: object
1894518945
properties:
18946-
listId:
18946+
list_id:
1894718947
type: string
1894818948
format: uuid
18949+
response:
18950+
$ref: '#/components/schemas/AmplitudeListResponseEnvelope'
1894918951
required:
18950-
- listId
18952+
- list_id
18953+
- response
18954+
AmplitudeListResponseEnvelope:
18955+
type: object
18956+
properties:
18957+
list_id:
18958+
type: string
18959+
format: uuid
18960+
required:
18961+
- list_id
1895118962
AuditLogList:
1895218963
type: object
1895318964
properties:

0 commit comments

Comments
 (0)