Customer deletion requests

When a customer asks you to delete their data, for example under GDPR or CCPA, you record it as a customer deletion request. There is no DELETE /v1/customers/{customer_id}. Every deletion goes through a request that someone on your side approves or rejects, and approval anonymizes the customer instead of erasing your sales history.

A request can start in two places:

  • The customer asks from their account. Flint's hosted customer account and accounts you build on /v1/me both let a signed-in customer request deletion. GET /v1/me/deletion-requests lists that customer's requests newest first, with the same status filter and paging as the merchant list, so an account can show where a request stands and when an earlier one was rejected.
  • You open it for them. Use this when the request arrives by email, phone, or a support ticket.

Both land in the same queue and follow the same review.

How a request moves#

status on customer deletion request
Final values do not change again
  • pending_review
    Waiting for your decision. Nothing about the customer has changed.
  • processing
    Approved. Flint is deleting the customer's data, and the customer can no longer be changed.
  • completedFinal
    The customer is anonymized.
  • rejectedFinal
    You declined the request. The customer can ask again later.
  • failed
    Deletion stopped because a subscription or saved card appeared during processing. Clear it and approve again.

A customer has at most one open request at a time. Asking again while one is pending_review, processing, or failed returns the existing request instead of creating a new one.

Receive a customer's request#

Subscribe to customer.deletion_requested so each request reaches a person or a ticket queue:

JSON
{
  "event_type": "customer.deletion_requested",
  "data": {
    "customer_deletion_request_id": "cdel_1kmn0aExample",
    "customer_id": "cus_1kmn0aExample",
    "status": "pending_review",
    "retention_policy": "retain_required_commerce_records",
    "requested_at": "2026-09-22T17:04:05Z"
  }
}

To review the queue without webhooks, list open requests:

cURL
curl "https://api.withflintpay.com/v1/customer-deletion-requests?status=pending_review" \
  -H "Authorization: Bearer YOUR_API_KEY"

The list filters by status and customer_id and pages with page_size (up to 100) and page_token. Reads need the customers.read scope; creating and resolving need customers.write.

Open a request yourself#

When the customer asks outside their account, create the request for them. The body must be empty:

cURL
curl -X POST https://api.withflintpay.com/v1/customers/cus_1kmn0aExample/deletion-requests \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Idempotency-Key: delete-cus-1kmn0a"
Response
{
  "data": {
    "customer_deletion_request_id": "cdel_1kmn0aExample",
    "customer_id": "cus_1kmn0aExample",
    "status": "pending_review",
    "retention_policy": "retain_required_commerce_records",
    "requested_at": "2026-09-22T17:04:05Z"
  }
}

The response is 202 Accepted, and customer.deletion_requested fires just as it does for a customer's own request. Confirm the requester's identity before you approve.

Clear subscriptions and saved cards#

Flint will not delete a customer who could still be charged. Before you approve:

  1. Cancel every subscription that is not already canceled. Cancel with {"cancel_immediately": true}; a subscription scheduled to cancel at period end still counts until that date. See Cancel.
  2. Remove every saved card that is active or pending. See Remove a card.
cURL
curl "https://api.withflintpay.com/v1/subscriptions?customer_id=cus_1kmn0aExample" \
  -H "Authorization: Bearer YOUR_API_KEY"

curl "https://api.withflintpay.com/v1/payment-methods?customer_id=cus_1kmn0aExample&status=pending" \
  -H "Authorization: Bearer YOUR_API_KEY"

The payment method list returns only active cards by default, so check pending separately as above.

Unpaid invoices and open orders do not block deletion. Collect, void, or write them off before approving if you need them settled.

Approve or reject#

cURL
curl -X POST https://api.withflintpay.com/v1/customer-deletion-requests/cdel_1kmn0aExample/resolve \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Idempotency-Key: resolve-cdel-1kmn0a" \
  -d '{"decision": "approve"}'
Response
{
  "data": {
    "customer_deletion_request_id": "cdel_1kmn0aExample",
    "customer_id": "cus_1kmn0aExample",
    "status": "processing",
    "retention_policy": "retain_required_commerce_records",
    "requested_at": "2026-09-22T17:04:05Z",
    "resolved_at": "2026-09-23T09:12:40Z"
  }
}
  • "decision": "approve" moves the request to processing. The customer's sessions end right away, and any change to the customer, such as saving a card or creating a subscription, fails with CUSTOMER_DELETION_PROCESSING.
  • "decision": "reject" moves it to rejected and fires customer.deletion_rejected. The customer is unchanged.
  • If a subscription or saved card remains, approval fails with CUSTOMER_DELETION_BLOCKED. The error message gives the counts.

Processing runs in the background and ends in completed, which fires customer.deletion_completed, or in failed. failed fires no event, so if customer.deletion_completed has not arrived, read the request:

cURL
curl https://api.withflintpay.com/v1/customers/cus_1kmn0aExample/deletion-requests/cdel_1kmn0aExample \
  -H "Authorization: Bearer YOUR_API_KEY"

A request fails when a subscription or saved card appears while it is processing. Clear it and approve the same request again. A failed request can be approved again but not rejected.

What Flint deletes and what it keeps#

When the request completes:

  • The customer record is anonymized. Its name becomes "Deleted customer". email, phone, billing_address, shipping_address, tax_identity, internal_note, metadata, external_reference_id, group_id, and default_payment_method_id are cleared. Saved addresses are deleted.
  • Saved cards keep no card details. The payment method records stay with their brand, last four digits, and expiry removed, and the processor no longer holds the card.
  • Sales history is kept. Orders, invoices, payments, and refunds stay for accounting and tax, with the customer's identity removed. retention_policy: "retain_required_commerce_records" reports this.
  • Email preferences are kept separately, so an unsubscribe is still honored. Flint stores a keyed marker, not the email address.

The anonymized customer still appears in GET /v1/customers/{customer_id} and in order and invoice history, so reports and refunds keep working. It cannot be changed or reactivated. If the same person comes back, create a new customer.

If you keep your own copy of the customer's data, in your database, CRM, or analytics, customer.deletion_completed is your cue to delete it.

Webhook events#

Each payload carries customer_deletion_request_id, customer_id, status, retention_policy, requested_at, and resolved_at once the request is resolved. Moving to processing or failed fires no event. Removing cards before approval fires payment_method.removed for each card; deletion itself does not.

Errors you will hit#

  • HTTP 409
    The customer still has a subscription that is not canceled, or an active or pending saved card. Clear them and approve again.
  • HTTP 409
    The customer is being deleted and cannot be changed.
  • HTTP 400
    The request was already resolved, the customer was already deleted, a failed request was rejected, or a list filter is invalid.
  • HTTP 404
    No customer or deletion request with that ID in this environment.

Common mistakes#

  • Canceling subscriptions at period end. A subscription with cancel_at_period_end still blocks approval. Cancel it immediately.
  • Checking only active cards. A card the customer started saving and abandoned is pending and still blocks approval. List with status=pending too.
  • Waiting for an event that never comes. A failed request fires nothing. If customer.deletion_completed does not arrive, read the request.
  • Expecting sales history to disappear. Orders, invoices, and payments stay, anonymized. Deletion removes who the customer was, not what they bought.
  • Keeping your own copy. Flint deletes its data, not yours. Handle customer.deletion_completed in every system that stores the customer.

Next steps#

Was this helpful?