List pending invites addressed to the caller's email
Lazy expiry — past-TTL rows are filtered out and status-flipped to `EXPIRED` in the background. The daily cron hard-deletes past-TTL rows overnight; this keeps the schema clean between runs without an extra scheduled job.
/api/user/invitesLazy expiry — past-TTL rows are filtered out and status-flipped to EXPIRED in the background. The daily cron hard-deletes past-TTL rows overnight; this keeps the schema clean between runs without an extra scheduled job.
Response Body
application/json
curl -X GET "https://loading/api/user/invites"[
{
"id": "inv_w7x8y9z0",
"role": "ADMIN",
"expiresAt": "2026-04-29T10:30:00.000Z",
"createdAt": "2026-04-26T10:30:00.000Z",
"organization": {
"id": "org_partner",
"name": "Partner Corp",
"image": "https://api.dicebear.com/9.x/shapes/svg?seed=partner"
},
"invitedBy": {
"name": "Riley Partner",
"email": "riley@partner-corp.com"
}
}
]Unregister a passkey DELETE
Same `(credentialID, userId)` scoping as rename. The account stays usable via other authenticators (OAuth, OTP) as long as at least one remains — there's no equivalent to the OAuth last-method guard here because passkey removal alone never strands a user.
Claim a pending invite POST
Atomic transaction — `Membership` create + invite `status → ACCEPTED` in one round-trip so a crash between writes can't leave a dangling PENDING row for someone who already has membership. Returns the org id + name so the client can navigate to it without a profile refetch.