# Erasure at providers

When your app sends a person's data to another company, such as a payment
provider, erasing the person also asks that provider to erase them. Two
declarations make that work. The provider's package declares, in its
`provider.jadpo`, which call erases a person and what it takes. Your app's
connection names the field that holds the person's key at that provider:

```jadpo
// packages/stripe/v2024_06_20/provider.jadpo
provider {
    ...
    erasure: {
        call: customers.delete
        by: CustomerId
    }
}

// app.jadpo
stripe: {
    package: Stripe.v2024_06_20
    domains: [payments]
    credential: config.stripe_secret_key
    erasure: {
        key: User.stripe_customer_id
    }
}
```

Erasure emits a `PersonErased` event, which holds the person entity's name,
the person's `id` and when they were erased, and nothing personal, besides
the keys below. The `erasure:` is a declaration on the package, not part of
any [capability](/docs/capabilities.md), so Stripe and Postmark
are erased the same way.

- **Your app first, then the providers.** When `User.erase` runs, Jadpo
  copies each connection's key, here `stripe_customer_id`, into the
  erasure event. It then erases the person in one transaction, as above.
  After that commits, a generated subscriber calls each provider's erasure
  operation, retried until the provider confirms. So a provider never
  holds the only record of someone your app still has.
- **The completion email waits for every provider.** The
  erasure-completed email, one of the
  [built-in emails](/docs/built-in-emails.md), goes only
  once every provider has confirmed. A delivery that gives up is parked
  for an operator and shown in the privacy request's state and in
  `jadpo privacy requests`. It is never left quietly incomplete.
- **A copied key that is itself personal data**, such as an email address
  used as the provider's key, stays only in the outbox until it is
  delivered. The personal-data report lists it there.
- **A connection that receives personal data but can't erase it** is a
  compile error. That is a connection whose package declares no
  `erasure:`, or which names no key, or reached with a driver rather than a
  package; or one whose key is on one person entity while it also receives
  the data of another. An
  [acceptance](/docs/acceptances.md), a committed file
  in which a person states why the data stays there (tax records at an
  accounting provider, say), allows it, and the report lists the
  connection and the reason:

  ```jadpo fragment
  /// Acme Books must keep invoices for seven years for tax.
  acceptance {
      changes: {
          accounting: ErasureNotPossible.data_stays
      }
  }
  ```

  It holds for as long as the connection keeps data, so a project that
  already sends some needs it as soon as a change is judged, and later
  changes need no other. Taking it away takes away what it allowed. It
  covers the connection: a new field sent there later needs no other
  acceptance, and shows in the approval review's difference of the report.
  A store of files on the server's own disk is no other company, so it
  needs none: a file goes with the records that hold it.
- **The declarations are checked**, since each lets a connection off that
  acceptance. `call:` is an operation of the package that changes something
  and takes only the key: one field of its input of the type `by:` names,
  any other optional
  ([`package.provider_invalid`](/docs/errors/package.provider_invalid.md)).
  `key:` is a field of a `person: true` entity, of that type
  ([`connection.value_invalid`](/docs/errors/connection.value_invalid.md)).
- **Anything else** your app sends data to, such as a CRM it calls
  through its own integration, can be erased by your own `PersonErased`
  subscribers.
