Bans & Fraud Signals
The admin operations that take a user out of circulation, the automated bans, and the fraud signals consulted during profile changes. Status effects are summarised in User Status.
Ban
POST /{user_id}/user/ban (BanUser); body optional (source, description).
-
An unknown user is
404; an alreadyBANNEDuser is a200no-op. -
The current membership, when one exists, is re-written with status
BANNED, eventBANNEDand thesourcefrom the body (falling back to the caller-derived source). -
The Subscription Service and the Float Service ban the user.
-
The user becomes
BANNED. -
With a
description, a note is added to the user in the Admin API. -
The Auth0 account is blocked and a full-scope cleanup message (raw
user_id) is queued for the janitor. -
200with an empty body; any failure after step 1 is500.
Clear
POST /{user_id}/user/clear (ClearUser) lifts a ban or investigation: a BANNED or INVESTIGATE user becomes PAUSED, the Auth0 account is unblocked, and the membership (when one exists) is re-written with status PAUSED, event MX_UNBLOCK and a cleared reactivation_date so the cooldown does not apply. 202 with an empty body. The user must then reactivate.
Flag
POST /{user_id}/user/flag (FlagUser) marks the user INVESTIGATE and re-writes the membership (when one exists) with status and event INVESTIGATE. 200 with an empty body. An INVESTIGATE user cannot reactivate and cannot be reached by the collect flow.
Chargeback Ban
The payment-worker Lambda consumes {env}-payments, filtered by Terraform to FLOAT_DEBIT_CHARGED_BACK and SUBSCRIPTION_CHARGED_BACK events. For a payment whose status is CHARGED_BACK it calls BanUser through the user-service client with source System and description user banned from user-service for returned payment — only when ENABLE_CHARGEBACK_BAN is true (it is false in both environments, so chargebacks are currently logged and skipped). A processing error reports the record as a batch item failure for retry.
Related Accounts
POST /users-by-related-accounts and POST /users-by-related-accounts/count find other users sharing identifiers with the request (user_id, phone_number, email, install_id):
found_by |
Match |
|---|---|
|
Users with the same phone number (DynamoDB and |
|
Users with the same Firebase install id; empty or |
|
Users with the same email |
|
Users the Payments Service reports as sharing a bank account hash; only when |
Source: pkg/api/users.go, pkg/api/models.go
The requesting user is excluded from the results. The count endpoint requires user_id (400 without it) and de-duplicates users across match types into unique_total; when RELATED_USERS_BAN_COUNT is greater than 0 (4 in prod) and unique_total exceeds it, the user is banned with source System and description Related users count exceeded ban threshold, and user.related_accounts.banned is emitted. In the test environment the list is capped at 10,000 rows.
Castle
Every self-service profile update is scored by Castle with a user-update-attempted request built from the raw HTTP request (client headers and address) and the user’s current and requested profile. With ENABLE_CASTLE_BLOCKING (true in both environments) a Castle error is 500, and a missing verdict or a deny policy action is 401; without the flag the verdict is logged only. Admin updates are not scored.
Pause Fraud Signal
A pause request from a user whose pause tag is SUB_PENDING_RESUME is allowed but emits user.membership.pauseFraud, marking a user who pauses again right before a collection — see Membership Pause.