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/meboth let a signed-in customer request deletion.GET /v1/me/deletion-requestslists that customer's requests newest first, with the samestatusfilter 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 requestA 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:
{
"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 "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 -X POST https://api.withflintpay.com/v1/customers/cus_1kmn0aExample/deletion-requests \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: delete-cus-1kmn0a"
{
"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:
- 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. - Remove every saved card that is
activeorpending. See Remove a card.
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 -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"}'
{
"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 toprocessing. The customer's sessions end right away, and any change to the customer, such as saving a card or creating a subscription, fails withCUSTOMER_DELETION_PROCESSING."decision": "reject"moves it torejectedand firescustomer.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 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, anddefault_payment_method_idare 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#
Common mistakes#
- Canceling subscriptions at period end. A subscription with
cancel_at_period_endstill blocks approval. Cancel it immediately. - Checking only active cards. A card the customer started saving and abandoned is
pendingand still blocks approval. List withstatus=pendingtoo. - Waiting for an event that never comes. A
failedrequest fires nothing. Ifcustomer.deletion_completeddoes 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_completedin every system that stores the customer.
Next steps#
- Customer accounts: where customers request deletion in the hosted account.
- Save a card and charge it later: list and remove a customer's saved cards.
- Subscription billing: cancel subscriptions immediately.
- Customers API Reference: every field on the customer.
