anon_email
Guides

Tenancy model

How the API keeps one account's data out of another's.

The API is multi-tenant: one deployment serves every account. Isolation is enforced at the application layer, because API Gateway sits between callers and DynamoDB and IAM sees only the API's own execution role, not the end user.

The rule is simple: keys are built from the token's sub claim, never from request input.

What that means per route

DataHow it is scoped
AliasesRead through an index partitioned by USER#<sub>; writes additionally carry an ownership condition.
RecipientsStored under USER#<sub> / RECIPIENT#<id>; the id alone cannot reach another account's item.
Profile, subscriptionStored under USER#<sub>; addressed only by the claim.
Alias addressesGlobally unique across all accounts, like any email address.

Because the partition key comes from the claim, a valid id from a different account simply matches nothing. Routes that look up a recipient by id therefore return 404, not 403 — the API does not confirm that a foreign id exists.

Why not request parameters

No route accepts a user_id or email-address owner. alias_id and recipient_id are opaque; they select within the caller's own partition. If you find yourself wanting to pass an owner, the route you want does not exist.

Conditions on writes

Reads are structurally scoped by the partition key. Mutations that reach an alias by its globally-unique address additionally carry user_sub = <caller> as a condition, so a race or a bug cannot rewrite someone else's alias.

Quotas

Alias and recipient counts live on the profile item and are moved in the same transaction as the create or delete that changes them, so a quota can never drift from the rows it counts. GET /account reports both counts; limits come from GET /subscription.

Deletion

DELETE /account removes the Cognito user and every item it owns. A hard delete, like aliases and recipients individually: there is no tombstone and no restore.

On this page