Metadata-Version: 2.4
Name: effaced-stripe
Version: 0.1.0
Summary: Stripe resolver for effaced — export and erase a data subject's PII held in Stripe.
Project-URL: Homepage, https://effaced.dev
Project-URL: Repository, https://github.com/jaylann/effaced
Project-URL: Issues, https://github.com/jaylann/effaced/issues
Project-URL: Changelog, https://github.com/jaylann/effaced/blob/main/packages/effaced-stripe/CHANGELOG.md
Author-email: Justin Lanfermann <Justin@Lanfermann.dev>
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: data-erasure,effaced,gdpr,privacy,stripe
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: effaced
Requires-Dist: stripe>=12.5
Description-Content-Type: text/markdown

# effaced-stripe

First-party [effaced](https://github.com/jaylann/effaced) resolver for
Stripe — export and erase a data subject's billing PII held in Stripe.

- **Export (Art. 15):** customer profile, addresses, and payment-method
  metadata.
- **Erase (Art. 17):** Stripe customer deletion, which Stripe itself
  implements as a GDPR-aware redaction.

```bash
uv add effaced effaced-stripe
```

```python
from effaced import ResolverRegistry, SubjectRef
from effaced_stripe import StripeResolver

registry = ResolverRegistry()
registry.register(StripeResolver(api_key="rk_live_..."))

# Refs of kind "stripe" are routed to this resolver; the value is the
# Stripe customer id.
ref = SubjectRef(kind="stripe", value="cus_...")
```

## Restricted-key setup

Don't hand the resolver your full secret key. Create a restricted key
(Dashboard → **Developers → API keys → Create restricted key**) with
exactly the permissions the resolver uses:

| Permission | Access | Used for |
|---|---|---|
| Customers | **Write** | retrieve for export, delete for erasure |
| Payment Methods | **Read** | payment-method metadata in exports |

Everything else stays **None**. A key missing one of these surfaces as a
non-retryable `ResolverError` the first time the saga touches Stripe.

## What gets exported — and what never is

Exported, when populated: customer `email`, `name`, `phone`, billing and
shipping addresses, and per payment method its `type`, card metadata
(`brand`, `last4`, `exp_month`, `exp_year`), and billing details.

Never exported:

- **Full card numbers.** Stripe does not expose PANs over its API, so no
  export from this resolver can ever contain one — don't let anyone tell
  you otherwise.
- **`metadata` dicts.** Their contents are defined by your application;
  the resolver cannot know what they hold. Export those fields through
  your own data map instead.

Changing the exported field set is behaviour under effaced's widened
SemVer: additions are MINOR, removals MAJOR.

## Idempotency & error semantics

- Erasing a customer Stripe no longer knows is **success**
  (`already_absent=True`), never an error — saga retries depend on it.
- Rate limits (429), connection faults, and Stripe-side errors (5xx)
  propagate so the saga runner retries with backoff. Bad or
  under-permissioned keys and malformed requests raise `ResolverError`
  and abandon fast. SDK-internal retries are disabled; the saga runner
  owns retry policy.

## Testing

No live calls: pass `http_client=` (any `stripe.HTTPClient`) to fake the
transport. The package is verified against the shared
`effaced.testing.ResolverConformanceSuite` — subclass it the same way to
certify your own resolver.

> **Not legal advice.** effaced provides technical mechanisms for
> implementing data-subject rights. It does not make you GDPR-compliant
> and does not constitute legal advice.

Licensed under Apache-2.0.
