What to log in your SaaS
A field guide to the events every SaaS ends up logging: auth, billing, admin actions, data requests. One page per action with a concrete payload and a retention hint.
Authentication
user.signupEmit a `user.signup` event when a new account is created. Store the source, referrer and any campaign metadata so you can trace paying customers back to the campaign that brought them in.
user.loginEmit a `user.login` event on every successful sign-in. Stores actor, IP, user agent and any MFA method used. Feeds your security dashboards, user timelines and enterprise audit exports.
user.login.failedEmit a `user.login.failed` event on every failed sign-in, whether the email exists or not. IP and outcome let you aggregate across a time window and spot distributed attacks before they convert.
user.password.changedEmit a `user.password.changed` event every time a user updates their own password, and distinguish it from `user.password.reset` (triggered from the forgot-password flow).
user.password.resetEmit a `user.password.reset` event when a user completes the forgot-password flow and a new password is set via an email token. Distinct from a normal password change.
user.mfa.enabledEmit a `user.mfa.enabled` event the first time a user successfully verifies a second factor, TOTP, WebAuthn, SMS. Enterprise contracts often require MFA adoption reporting.
user.session.revokedEmit a `user.session.revoked` event when you terminate a session, whether the user clicked 'sign out everywhere', or your back end killed it due to suspicious activity, or an admin revoked it.
Billing
invoice.paidEmit an `invoice.paid` event from your Stripe (or other provider) webhook handler. Store the amount, currency, provider event id and the customer's organization.
invoice.payment_failedEmit an `invoice.payment_failed` event whenever a charge attempt fails, at initial capture, on retry, or after the card was updated.
invoice.refundedEmit an `invoice.refunded` event on every partial or full refund. Include the reason, customer request, accidental charge, chargeback.
subscription.upgradedEmit a `subscription.upgraded` event every time a customer moves to a higher-tier plan. Keep the from/to plan slugs in metadata for cohort analysis.
subscription.cancelledEmit a `subscription.cancelled` event as soon as a customer asks to cancel, even before the period ends. Store the reason from your cancel flow if you have one.
Admin & compliance
admin.user.suspendedEmit an `admin.user.suspended` event whenever a staff member suspends a customer from your back-office. Always attach a reason, it is the first thing legal will ask for.
admin.role.changedEmit an `admin.role.changed` event every time a staff member updates a user's or a team member's role. Keep the from/to role names as metadata.
admin.impersonation.startedEmit an `admin.impersonation.started` event whenever a staff member impersonates a customer for debugging or support. Emit `admin.impersonation.ended` when the session is closed.
data.export.requestedEmit a `data.export.requested` event every time a user or an admin exports personal data. GDPR Article 15 gives users a right of access, emit the event the moment the export is queued.
user.account.deletedEmit a `user.account.deleted` event when you process a deletion request. Pair it with a call to `DELETE /v1/actors/:id` to anonymize the rest of the trail.
Content & storage
file.uploadedEmit a `file.uploaded` event after a file is committed to your object storage. Store the filename, size and mime type so you can answer 'who uploaded this PDF last week'.
file.deletedEmit a `file.deleted` event whenever a file is removed from your storage, whether by a user or a retention job.
document.sharedEmit a `document.shared` event whenever a user generates a share link, invites a recipient, or changes the visibility of a document.
AI agents
agent.tool_calledEmit an `agent.tool_called` event the moment your AI agent decides to invoke a tool, before the tool runs. Captures the agent identity, the tool name, the arguments and the user who triggered the conversation. Pairs with `agent.tool_returned` for full traceability.
agent.tool_returnedEmit an `agent.tool_returned` event right after a tool finishes, before handing control back to the model. Stores the result status (success or failure), the duration and any error. Critical for diagnosing slow or flaky tools that derail an agent.
agent.action_takenEmit a domain event with `actor.type` set to 'agent' for the actual change your agent performed (file.deleted, invoice.refunded, project.archived). This is the audit-grade record customers and auditors will look at first when something is disputed.