Per My Last Webhook
Features Install Terms GitHub

Privacy Policy

Effective date: 2026-09-27
Operator: Per My Last Webhook, LLC (206 W Ironwood Dr, PMB 1114, Coeur d'Alene, ID 83814)
Contact: hello@permylastwebhook.com

1. Who this applies to

This policy describes the data that Per My Last Webhook ("the Service") collects when your Microsoft 365 organization installs and uses it. The Service is operated by Per My Last Webhook, LLC (an Idaho limited liability company).

If you have not installed the Service into your Microsoft 365 tenant, this policy does not apply to you.

2. What we collect

The Service is a webhook relay: events from your CI/CD, GitOps, observability, and incident tools enter on one side, Adaptive Cards land in Microsoft Teams on the other. To do that we process and store the following.

2.1 Tenant and identity data

DataSourceWhy we have it
Microsoft Entra tenant idBearer token tid claimMulti-tenant scoping; ensures one customer cannot see another's data
User principal name (UPN) of admins who use the management API or admin UIBearer token preferred_usernameAudit-log attribution for sensitive actions
Admin-consent timestampEntra /adminconsent callbackProof that an authorized admin granted access
Entra object id and display name of people you name in a subscription (on-call DM target, "@mention on failure" owners)Entered by your admin in the admin UISo the bot can DM or @mention them
Entra object id, Teams user id, and display name of anyone who messages the bot 1:1Bot Framework conversationUpdate / message activitiesPopulates the on-call DM picker; needed to open a 1:1 chat proactively

So we do hold names and directory identifiers for a small set of people in your tenant: your admins, and the people your admins point the bot at or who talk to the bot. We do not collect email addresses beyond the UPN (which usually contains one), phone numbers, or any other personal data about end-users.

2.2 Subscription configuration

For each subscription an admin creates, we store:

  • A user-supplied subscription name (free-form, e.g. #builds-team-a).
  • The delivery destination: a Microsoft Teams Workflows incoming-webhook URL, a Teams channel conversation reference, or a person to DM. Webhook URLs are stored in Azure Cosmos DB, which encrypts all data at rest; they are never written to logs and are never returned by any API after creation (responses carry a hasTeamsWebhookUrl boolean instead). They are not stored in Azure Key Vault.
  • A salted SHA-256 hash of the subscription's ingest API key (never the key itself).
  • Optional filters, routing rules, noise controls, quiet hours, incident-mode and branding settings, and (for the generic platform) a field mapping.
  • The source platform (one of the 16 supported tools, legacy MessageCard, or generic JSON).

2.3 Event payloads

When a tool emits an event, the Service receives a payload describing it (repository name, branch, commit SHA, author, status, build URL, log URL, alert text, and so on). The Service:

  • Normalizes it and posts an Adaptive Card to your Teams destination.
  • Records a delivery-health entry per subscription (success/failure, timestamp, error text, pipeline name, event status) so the admin UI can show "last delivery". Kept 30 days.
  • In incident mode, keeps an open-incident record (pipeline name, failure count, card id) until the incident resolves; kept 30 days.
  • For deduplication and "failure-after-success" filtering, keeps a small per-(pipeline, status) key for the configured window (up to 24 hours, outcome keys up to 30 days).
  • When the operator has enabled queued dispatch (DISPATCH_MODE=queue), the raw payload is placed on Azure Service Bus until a worker delivers it, and Service Bus retains undeliverable messages for up to 14 days. The hosted production service currently runs in inline mode and does not queue raw payloads.

Outside of those records, the raw payload is discarded after the delivery attempt completes. We do not build a searchable archive of your events.

2.4 Bot Framework data

When the bot is added to a channel or a person opens a 1:1 chat with it, we store:

  • Teams channel ids, team/channel display names, and conversation references for channels where the bot is installed.
  • The identifiers described in 2.1 for people who message the bot 1:1.
  • Activity ids of cards the bot has posted, to support in-place updates (kept 30 days).

The channel record is removed when the bot is removed from that channel. Other records persist until deleted on request (see 7).

2.5 Audit log

Every mutation on the management plane (creating, editing, deleting a subscription; rotating an API key) is appended to an audit-log entry containing: the actor's UPN or "host-key", the action name, the affected entity id, before/after snapshots with credentials redacted, and a timestamp. Approval decisions are also recorded; because the approve/reject link is a per-approval secret rather than a signed-in action, the decision is attributed as "anonymous".

Audit entries are stored for 90 days then automatically deleted by Cosmos DB TTL.

2.6 Billing data (paid plans only)

If your tenant subscribes to a paid plan via Stripe:

  • We store your Stripe customer id, your Stripe subscription id, the plan tier, and the timestamp/id of the Stripe event that last changed it.
  • When an admin starts a checkout we store a record of that request so that a retry cannot charge you twice: the Stripe Checkout Session id, the time, and the details sent to Stripe, which include the email address (UPN) of the admin who started it. The record stays on your installation until a later checkout replaces it or your data is deleted.
  • We do not store your credit card number, CVV, or any other payment instrument. Stripe handles all payment data directly; we only receive identifiers and lifecycle events.

2.7 Rate-limit counters

To enforce per-organization rate limits we keep a short-lived token-bucket counter keyed by your tenant id — in process memory, or in Azure Managed Redis when the operator has enabled it. Counters expire within an hour of last use and contain no event content.

2.8 Operational telemetry

The Service emits standard application telemetry (request paths with query secrets scrubbed, status codes, durations, error stack traces) to Microsoft Application Insights / Azure Log Analytics. Personal data is not intentionally written to telemetry; webhook URLs, API keys, tokens, and passwords are redacted before emission. If a stack trace incidentally contains a user id, it remains subject to the same access controls as everything else. Telemetry is retained for 30 days.

3. What we do not collect

  • Source code.
  • The contents of your repositories.
  • Pipeline secrets (e.g. GITHUB_TOKEN, AZURE_CREDENTIALS). These may transit the Service as part of a webhook payload, but are not persisted beyond the records in 2.3.
  • Personal data about end-users of your CI system beyond what appears in event metadata (typically a username and an avatar URL) and the people listed in 2.1.
  • Cookies. The admin UI keeps its sign-in state in browser sessionStorage and your theme preference in localStorage; the only cookie the Service sets is a short-lived cookie during the install/admin-consent flow, used to bind the consent callback to the browser that started it.

4. How we use the data

We use the data above solely to:

  1. Deliver Adaptive Cards to your Teams channels, chats, and people.
  2. Authenticate you when you sign in to the admin UI or call the management API.
  3. Enforce per-organization rate limits to protect the Service.
  4. Show delivery health and provide an audit trail of who changed what.
  5. Bill you if you are on a paid plan.

We do not sell data. We do not share data with advertisers. We do not train AI models on your data.

5. Sub-processors

The Service runs on third-party infrastructure. The following sub-processors necessarily receive your data:

Sub-processorPurposeData shared
Microsoft Azure — Azure FunctionsComputeAll Service data in transit
Microsoft Azure — Cosmos DBPrimary data store (subscriptions, approvals, audit, installations, bot channels/messages/users, incidents, delivery state, install nonces)All stored Service data
Microsoft Azure — Service BusQueued dispatch (only when the operator enables queue mode)Raw event payloads, up to 14 days
Microsoft Azure — Key VaultOperator application secrets (bot password, Entra client secret, Stripe keys, API-key hashing pepper)No customer data
Microsoft Azure — Managed RedisDistributed rate-limit counters (when enabled)Tenant id, request counts
Microsoft Azure — Application Insights / Log AnalyticsTelemetryRequest metadata, error traces (secrets scrubbed)
Microsoft Teams / Bot FrameworkDelivery channelConversation ids, user ids, card payloads
Microsoft Entra IDAuthentication and admin consentTenant id, UPN
Stripe, Inc. (paid plans only)Payment processingStripe customer id, plan tier, plan lifecycle events

We do not engage additional sub-processors without updating this policy.

6. Where the data lives

Service data is hosted in the Central US (centralus) Azure region (United States). Disaster-recovery backups, when present, remain within the same geography.

If you require data residency in another region, contact us at hello@permylastwebhook.com.

7. Retention and deletion

Data classRetention
Subscriptions, installations, bot channels, bot usersUntil you delete them in the admin UI/API, or until we delete them on request
Bot channel recordRemoved automatically when the bot is removed from that channel
Approvals24 hours by default; configurable up to 7 days (auto-deleted by Cosmos DB TTL)
Audit log entries90 days (auto-deleted by Cosmos DB TTL)
Delivery health, incident records, bot card ids30 days (auto-deleted by Cosmos DB TTL)
Dedupe / recovery keysThe configured dedupe window (≤ 24 h); recovery keys up to 30 days
Queued raw payloads (queue mode only)Until delivered, at most 14 days on Service Bus
Install-flow nonces10 minutes
Rate-limit counters≤ 1 hour after last use
Telemetry30 days (Log Analytics workspace setting)
Stripe recordsHeld by Stripe until the customer record is deleted there. Deleting your data from the Service does not delete it; ask us and we will delete the Stripe customer as well

Uninstalling the Service from Teams does not automatically purge your data. Removing the bot from a channel deletes that channel's record; subscriptions, installation, and other records remain (so a re-install picks up where you left off) until you delete them yourself or ask us to. Uninstalling does not cancel a paid subscription either; cancel it from the billing page first. To request deletion of all data for your tenant, email hello@permylastwebhook.com from an admin account of that tenant; we complete deletion requests within 30 days, and we cancel any subscription that is still billing before we delete. Telemetry already collected is not deleted on request; it expires by TTL as above.

8. Your rights

Depending on where you are based, you may have the right to:

  • Access the data we hold about you.
  • Correct inaccurate data.
  • Delete your data.
  • Object to processing.
  • Receive a portable copy of your data.

To exercise any of these rights, email hello@permylastwebhook.com. We respond within 30 days. We may require proof that the request comes from an authorized admin of the affected tenant.

9. Security

  • Customer data is stored in Azure Cosmos DB, encrypted at rest by Azure and in transit with TLS 1.2+. The application reaches it with a managed identity, not a shared key.
  • Operator secrets (bot password, Entra client secret, Stripe keys, the API-key hashing pepper) are stored in Azure Key Vault with managed-identity access only. Subscription API keys are stored only as salted hashes.
  • Management endpoints require Microsoft Entra Bearer tokens validated against the multi-tenant JWKS endpoint, from a tenant that completed admin consent, carrying the admin app role.
  • Per-organization rate limits, applied after authentication, limit enumeration and abuse.
  • HTTPS is mandatory; the Function App is configured HTTPS-only and rejects plain HTTP.
  • Audit-log entries are append-only.
  • Inbound webhook signatures (GitHub, GitLab, Jenkins, CircleCI, Buildkite) are verified when the operator configures the corresponding secret; the per-subscription API key is always required.

We follow standard secure-development practices but make no warranty of perfect security. Report security issues to security@permylastwebhook.com.

10. Children

The Service is not directed at children under 16 and we do not knowingly process their data.

11. International transfers

If you are based outside the United States, your data is transferred to and processed in the Azure region listed in section 6. We rely on Microsoft's Standard Contractual Clauses for cross-border transfers within the Microsoft cloud.

12. Changes to this policy

We will update this policy when our practices change. The Effective date at the top of this page reflects the most recent revision. Material changes will be announced in the admin UI at least 30 days before they take effect.

13. Contact

Per My Last Webhook, LLC
206 W Ironwood Dr, PMB 1114, Coeur d'Alene, ID 83814
hello@permylastwebhook.com

For data-protection-specific inquiries: privacy@permylastwebhook.com

Per My Last Webhook

© 2026 Per My Last Webhook, LLC.

Product Features Install
Legal Privacy Terms
Code GitHub