Skip to content

effaced-stripe

effaced-stripe — first-party Stripe resolver for effaced.

class StripeResolver:
def __init__(api_key: str, *, http_client: HTTPClient | None = None) -> None

Exports, erases, and rectifies a subject’s PII held in Stripe.

Expects refs of kind "stripe" (refs are routed to the resolver whose name equals their kind — ADR 0008) whose value is the Stripe customer id. Erasure uses Stripe’s customer deletion, which Stripe itself implements as a GDPR-aware redaction.

Idempotency: a customer Stripe no longer knows yields already_absent=True on erasure and already_consistent=True on rectification — success, never an error. Rectification is convergent and structurally satisfies RectifyingResolver (see rectify_subject for the curated category mapping).

Error taxonomy (see effaced_stripe.errors): authentication, permission, and malformed-request failures raise ResolverError; rate limits, connection faults, and Stripe-side errors propagate so the saga runner retries. SDK-internal retries are disabled (max_network_retries=0) — the saga runner owns retry and backoff (ADR 0010).

Fields:

  • covered_surface (CoveredSurface): The Stripe PII this resolver claims to reach (AttestingResolver). Returns: STRIPE_COVERED_SURFACE, built from the exporter’s field tuples so it cannot drift.
  • name (str): Stable resolver name recorded in manifests and audits.
async def erase_subject(ref: SubjectRef) -> ResolverErasure

Delete the customer in Stripe (Art. 17).

Args:

  • ref (SubjectRef): kind="stripe", value=<customer id>.

Returns:

  • ResolverErasure — The outcome; already_absent=True if Stripe already had no
  • ResolverErasure — such customer.

Raises:

  • ResolverError — The key is invalid, lacks a permission, or the request was malformed — retrying cannot succeed.
async def export_subject(ref: SubjectRef) -> ResolverExport

Collect the customer’s Stripe-held PII (Art. 15).

Args:

  • ref (SubjectRef): kind="stripe", value=<customer id>.

Returns:

  • ResolverExport — Customer profile, addresses, and payment-method metadata —
  • ResolverExport — never full card numbers (Stripe does not expose them). Empty
  • ResolverExport — when Stripe holds no such customer.

Raises:

  • ResolverError — The key is invalid, lacks a permission, or the request was malformed — retrying cannot succeed.
async def rectify_subject(ref: SubjectRef, corrections: tuple[Correction, ...]) -> ResolverRectification

Apply category-keyed corrections to the customer (Art. 16).

Maps corrections onto Stripe Customer fields through a curated, single-field-per-category table: PiiCategory.IDENTITY to name and PiiCategory.CONTACT to email. Every other category is ignored — a category that maps to no field is a complete answer, not a failure (ADR 0013).

Deliberate limitation: Stripe also files phone and the address.* components under PiiCategory.CONTACT, but a coarse category-keyed scalar cannot tell email from phone from a postal address. Writing one value to all three would manufacture fresh inaccuracy, which Art. 16 exists to prevent — so only email is rectified for CONTACT. Field-keyed corrections are left to a future, finer vocabulary.

Convergence: the customer is retrieved first; only fields that actually drift from their correction are written, and a customer Stripe no longer holds is reported already_consistent=True. Re-applying corrections Stripe already reflects writes nothing and returns already_consistent=True — the rectification analogue of erasure’s already_absent, which saga retries depend on.

Args:

  • ref (SubjectRef): kind="stripe", value=<customer id>.
  • corrections (tuple[Correction, ...]): Category-keyed corrected values to apply.

Returns:

  • ResolverRectification — The outcome; already_consistent=True when nothing mapped,
  • ResolverRectification — the customer was absent, or Stripe already held every target
  • ResolverRectification — value.

Raises:

  • ResolverError — The key is invalid, lacks a permission, or the request was malformed — retrying cannot succeed.