Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to delete a price using API #658

Open
moskrc opened this issue May 26, 2020 · 82 comments
Open

How to delete a price using API #658

moskrc opened this issue May 26, 2020 · 82 comments

Comments

@moskrc
Copy link

moskrc commented May 26, 2020

Hello,

I want to delete a price inside a product, I can do it in the Stripe dashboard, but I can’t do this using API

Code:

stripe.Price.delete("price_HLez6Zi58HejNP")

Result:

  File "../src/payments/models.py", line 81, in delete
    stripe.Price.delete(self.stripe_id)
AttributeError: type object 'Price' has no attribute 'delete'

Thanks

@remi-stripe
Copy link
Contributor

@moskrc The Price API does not support deletion today. You should instead set active to false on the Price if you don't want to use it again. The only case where a Price can be deleted is when it's mirroring a Plan and this plan is deleted via the API, which we only support for legacy integrations but actively discourage using.

@remi-stripe remi-stripe self-assigned this May 26, 2020
@kirk-marple
Copy link

@remi-stripe On this topic, if you don't delete a price, which has been added to a product, you get an error deleting the product.

This product cannot be deleted because it has one or more user-created prices.

Should we just be setting products to inactive too, rather than deleting them?

@remi-stripe
Copy link
Contributor

Yes we recommend keeping your object so that it can help with future reconciliations.

@sasokovacic
Copy link

sasokovacic commented Mar 1, 2021

@remi-stripe It doesn't make any sense to be able to delete an unused product and not be able to delete an unused price. It's also not logical that we can delete a price in the Stripe panel but not through the API. You should enable this at least in the development mode where we are adding a lot of dummy data and want to clear some of it after testing. The only option here is to delete all test data from the Stripe panel.

@remi-stripe
Copy link
Contributor

@sasokovacic I agree but in the future we want to remove the ability to delete object and instead default to marking them as inactive and make them hidden. The Prices API is a newer API and replaces the Plans API. Plans could be deleted though so we had to support deletion in the Dashboard for backwards compatibility. If we had removed it, we'd have broken thousands of integrations that expect this flow to works in the Dashboard. Overall though, we are moving away from it and will, in the (far) future, disable this feature. For newer integrations, deleting a Price is something we don't want to directly support which is why you can't do it in the API

@jleclanche
Copy link
Contributor

@remi-stripe I know this is OT for stripe-python but IMO Stripe should consider allowing deletion of prices that haven't been used anywhere. Especially for users doing most of their business directly from the dashboard (eg. using Stripe purely as an invoicing platform), mistakenly creating prices can happen and if no related invoice has been issued, it ought to be fine to delete.

@remi-stripe
Copy link
Contributor

@jleclanche It's really confusing when an API fails in almost all cases though. Being able to delete a Price never used but not delete another Price is a pit of failure for a developer to discover. And FWIW We do allow this in the Dashboard already for that reason.
Overall there's no reason to delete a Price as long as the Dashboard is hiding them by default so it's more that we need to improve the Dashboard overall and not clutter the API with an API method that can almost never be used I think

@sasokovacic
Copy link

@remi-stripe what is the reasoning behind this decision? What is so problematic about deleting unused records? It's the most basic functionality in any application. When I build apps for businesses, I always implement soft deletion, but they are also able to hard delete data that doesn't have any value in the system. This is how you enable users to clean up the database frequently and consistently.

@remi-stripe
Copy link
Contributor

@sasokovacic It's related to what I mentioned. You would think you can delete all prices but later discover you can only delete unused prices for example. And if you support price deletion, then in the API you get a truncated version of the object that only returns the id, object and deleted property when what most integrations want is to make the price inactive so that no one new can use it, while keeping the historical record.
I do understand your position and I don't disagree but I wouldn't call it "the most basic functionality" either. At some scale, there is value in data that can be mutated or disappear too.

@QuintinWillison
Copy link

QuintinWillison commented Apr 2, 2021

I've just stumbled across this issue as I'm working on the "product and price" creation bit of a Stripe integration for someone right now (JS SDK in Node.js but applies just the same, and this issue came up top in Google search). It really makes no sense to me why the "..." menu against a price in the dashboard (the web UI) allows users to "Delete price" but I cannot do the same from the API.

Also, loosely related, I was surprised I could create products and specify the product id myself (good!) but found that I am not allowed to specify the price id myself when creating a price.

Something definitely doesn't sit right here. I was expecting consistency and parity from Stripe across all levels of the UX/DX, given how focussed you are on API / developer first (or at least as far as I understood you were). It just feels a bit curiously incongruous. 🤷

Developers just learning your platform will be thrashing about, in both test and production environments, so I think it's only natural to be able to fix our mistakes by deleting unused and misconfigured objects while we experiment... especially when those experiments are programs / scripts that we're writing to "initialise" our Stripe environments.

@sasokovacic
Copy link

@remi-stripe from my experience deletion/soft-deletion is the most basic and most common functionality these days. Also, there is a difference between archived, soft-deleted, and hard-deleted status. IMO Stripe should have at least the first two available through its API. As for truncated objects, you don't have to return them. There is no need for this. You only return active objects by default. Archived and soft-deleted objects can be retrieved explicitly using some parameter or different URI. In the end, it's your decision. I'm just sharing my experiences building many business apps. Some businesses require hard deletion, but most of them require soft-deletion which means these records are not visible anywhere in the app except in some special view for troubleshooting purposes.

@pm-bc
Copy link

pm-bc commented Apr 15, 2021

I will second the comments from Quintin and sasokovacic. I just ran into this myself when attempting to use the API to completely automate some testing our accounting team is doing --- in the test area! Lo and behold I can't use the API to clean up a bunch of test prices, and, well, that really stinks. I see zero reason why deleting prices via the API should be blocked from the test environment.

Second, I even feel that in the production area, it should be allowed as well via API. First, it's the end user's data, and if they make a mistake and want it GONE, that should be their choice. Since people (and especially accountants -- haha!) make mistakes a lot, and since there are numbers involved and the potential for fat-fingering, a good UX for an API-centric product like Stripe is supposed to be would allow this --- or at least give the user the ability to enable such a 'feature' themselves. It's fine if Stripe wants to think that they need to hold everyone's hand on everything, but you don't. If you want to have a default mode where it is disabled, fine, but give us the ability to enable it and use it if we know what we're doing. And we do.

Just food for thought. Thanks for reading.

@remi-stripe
Copy link
Contributor

I see zero reason why deleting prices via the API should be blocked from the test environment.

One reason is that if we didn't block it, you'd build your entire integration thinking it will just work in Live mode only to discover you're down the day you deploy to production. Consistency between Test mode and Live mode is quite crucial for patterns like this and we do our best to approach it this way when we can

As for the second part of your comment, I don't disagree conceptually but we used to support deletion on the Plan API and I have helped countless developers over the years try to recover from deleting the wrong Plan, re-creating a new Plan with the same id and then being thoroughly confused why 2 subscriptions on the "same plan id" had a different amount charged, etc. There is a lot more to it than just deleting to suppress a mistake and over the years as business grows there is a higher cost than you would expect to supporting real deletion in the API.
It doesn't mean we won't bring it back, we're constantly monitoring feedback like this and taking it into account as we evolve our products and APIs and we hear you. I have also shared this thread multiple times internally as we looked into future improvements and changes so it's top of mind for the eng teams maintaining those APIs overall!

@sasokovacic
Copy link

sasokovacic commented Apr 16, 2021

@remi-stripe thats why I suggested soft-deletion. This is how you prevent users from doing hard-deletion mistakes and they can do a recovery when they soft-delete something. This is what businesses mostly require from my experiences. Soft-delete should be the default behaviour. As for hard-delete, I agree with pm-bc. Users should be able to remove all their content from the platform if they want. But it should be done explicitely which means you should send some extra parameter in the request or use different URI.
I do agree with you about consistency. This should be available on both environments.

@kg69design
Copy link

kg69design commented May 12, 2021

@remi-stripe If you monitoring feedback, please, check these real-world examples.

  1. I created 1000+ products thought API with prices. And now these product need to be deleted. What should I do? Delete them manually one-by-one? Or mark them as "Archive" and use search-filter EVERY time when I need to edit products in admin-area?
  2. I created 20+ different prices to one product and now these prices need to be deleted. What should I do again? Delete them manually too? Or mark them as "Archive"? But have your ever try to create or edit price in a product with tons of "Archive" prises?

The main reason of all problems like that is that you do not use your soft by yourselves in real world and do not want to notice the obvious things that make working with your application very difficult.

@remi-stripe
Copy link
Contributor

@kg69design Thanks for the feedback, we'll see if we can make improvements to the Dashboard to make those flows better.

@boatcoder
Copy link

Looks like you should read up on db constraints @remi-stripe. Things that are unused should be deletable, things that are in use can only be made inactive. It's worked for relational DBs since the 60s. I know you don't care, you just want to make one of your pain points be someone else's pain point and you have succeeded in doing exactly that.

@arian-fallahpour
Copy link

Also, whenever you want to test a certain product during development, you might want to delete it later on so it doesn't clutter everything up. I run into a lot of situations were I quickly create a new product to test the integration of my API with stripe, then have to manually delete it later.

@nicholi
Copy link

nicholi commented Sep 23, 2021

Addendum about Price object usage. It's not just the usage in active Subscriptions which will make it undeletable. I noticed creating new Invoices from within the dashboard will create a "one-time" interval Price object. Also you can accidentally create the same price value twice in two objects (if you manually enter the value amount rather than select from dropdown in Product selection). Once this price_id gets used in a finalized Invoice, now it's basically undeletable because it is used in 1 transaction. As invoices can never be removed, and now it's part of that transaction history. Can only archive and ignore clutter in Dashboard. Not part of any active Subscriptions at all.

I fully understand the necessity to keep these objects around for the transaction history of an invoice (which is meant to be eternal). Hoping we can get a more ignore/soft delete type feature, as long as the Price object is removed from any active transactions and its only existence is in old invoices like these. As sometimes we literally do not need the Price object anymore (and possibly created in err or in testing), and the only thing it does is clutter lists in Dashboard as archived and requires being filtered out in list calls to API as well (even though that is fairly simple to handle as well, by default it would be listed though).

@boatcoder
Copy link

boatcoder commented Sep 23, 2021 via email

@MehdiSaffar
Copy link

Truncate test data or bulk deletion/update active state would be very helpful

@olan-a21
Copy link

olan-a21 commented Dec 9, 2021

Deleting a price should be in any environment. There are many reasons a delete should be implemented. If users want to delete them, allow it, it's their choice if they want to delete or archive them.

@zefir-git
Copy link

If deletion of prices is impossible, perhaps then listing all prices should by default be active=true and if someone needs to list all inactive/archived prices (for whatever reason), they could send a different API request to see just these. Similarly, in the dashboard, archived prices could be filtered out from suggestions when creating new products or invoices. Basically, archiving a price would soft-delete it, allowing you to still get it by ID, but it is not actively displayed on the Dashboard or in the default prices list, reducing the processing of useless data with the API that is required to be there for archival/log purposes and making the dashboard UI cleaner.

However, I can see how such a change in the API could break applications that use archived prices differently than me, so perhaps developers that do not want to see archived prices in lists should just always use active=true in their API requests to filter out inactive prices.

@top-master
Copy link

top-master commented Apr 6, 2022

In my case, I just wanted to migrate form Plans to Prices, but all these deleting errors show up.

Because you seem to force setting active=false (instead of deleting).

Now, please force that kindly on us developers, you ask "how?", well, like whenever we call delete(...), you should silently set active=false and save(...) (also, fix your Dashboard to really hide Prices).

@boatcoder
Copy link

I think @top-master you have been fooled into thinking they care, based on the way this is STILL broken after a full year, it is obvious, they don't

@remi-stripe
Copy link
Contributor

@boatcoder that's a pretty surprising comment. We do care, we listen to feedback, we explain our thought process and we also try to clarify why we do things a certain way. We've built dozens of features based on feedback from developers here, on public mailing list, on our Discord server or to support.

We won't be able to build everything though and we don't always agree that something should be built or designed in a certain way. For example we disagree that deleting should not delete and subtly marked it as inactive but still existing. It's not wrong, but it's also not how deletion has worked historically in our API.

That definitely doesn't mean we don't care and that we don't listen.

@boatcoder
Copy link

boatcoder commented Apr 8, 2022 via email

@matthewlloyd
Copy link

Can you say with complete confidence that no developer out there would be confused by this

Yes. With an appropriately worded error message, and a note in the documentation, I find it extremely unlikely that any developer capable of using the Stripe APIs would be confused by this. For example:

"Prices can only be deleted if they have not been used by any payments."
"Prices cannot be deleted after they become associated with payments."

On the other hand, here in this thread, we have dozens of developers who have already been confused by the fact that you can't delete a price.

and similarly that no developer out there would ever think to use this in production without realizing this is forbidden there?

Well clearly we already have lots of developers here who have thought to use this in production, actually written code to use Price.delete(), and already discovered the hard way that it doesn't work. There are a lucky few who have stumbled upon this thread, but likely many others who are just left confused as to why Product has a delete method, but Price doesn't.

I really don't see how making it only work in test mode, or in both test and production mode but only when the price object has not been used, could make the situation any more confusing or irritating than it currently is.

@remi-stripe
Copy link
Contributor

I'm sorry, but the absence of a Price Delete API means no one can go to production thinking it exists and discover the hard way it doesn't.

On the other hand, if the method did exist but had the limitation you're all discussing, then the majority of developers would discover this the hard way in production when suddenly deletion (which they thought would just work) errors.

I understand the frustration, and I don't disagree with the ask to simply support real deletion (whether the Price is used or not). I disagree though that just supporting this in the API with a clear error is a good developer experience.

@matthewlloyd
Copy link

No problem, since Stripe doesn't seem to care to listen to feedback from its own customers, I have decided to switch my integration to PayPal and Square Payments over the long term, so this won't be an issue for me.

@pm-bc
Copy link

pm-bc commented Feb 13, 2023 via email

@aral
Copy link

aral commented May 8, 2023

@remi-stripe You must be getting as frustrated with this discussion as the folks running into the issue are given it’s been active for two years now apparently.

My take (that no one asked for):

  1. Parity between test and live modes is a core expectation and you’re right not to break it (nor should you).
  2. You should be able to allow the deletion of unused prices in both test and live modes without any negative impact

I have a feeling that implementing the second point would alleviate the concerns of the majority of the folks here (including me; I just ran into this issue myself, leading me to this thread) while also meeting the needs you’ve articulated in the thread.

Regardless, hope everyone’s having a good start to the week and let’s try not to gang up on Remi, folks. It can’t be fun for them either.

@ROBERT-MCDOWELL
Copy link

@aral
it looks like this @remi-stripe is an A.I. anyhow ;)

@aral
Copy link

aral commented May 8, 2023

Not ideal, but one imperfect workaround to this issue – especially if your needs are simple – is to only ever create one price for any given currency and subscription period with a unit cost of 1. Then you can adjust the unit amount to whatever you like and never have to edit the price. I just remembered that I’m actually using this approach for our donation widget at Small Technology Foundation and it works great for our needs there.

(We’re only using whole numbers there but I guess you could use it for any amount by setting the price to 0.01.)

Again, not perfect and not useful for every use case but sharing it here since (a) I’m using it in production on at least one project and (b) it might help someone else out.

I might actually end up using this technique for Domain also since people will be able to change the price of the subscription from their dashboards and I don’t want it to create an endless stream of prices and have to manage whether they’re active or not.

@aral
Copy link

aral commented May 8, 2023

@aral it looks like this @remi-stripe is an A.I. anyhow ;)

Exactly the kind of unhelpful comment we don’t need, Robert. C’mon, now. Put yourself in their place and read your comment. How does it make you feel?

@ROBERT-MCDOWELL
Copy link

@aral do you really think that all the comments after 2 years here helped anything to solve it?

@remi-stripe
Copy link
Contributor

remi-stripe commented May 8, 2023

You should be able to allow the deletion of unused prices in both test and live modes without any negative impact

That's an idea and why some of exceptions are allowed in the Dashboard. The risk is that it's easy to think you can delete a Price after something like this and not realize it only works with unused Prices. But that's something we're considering.

Not ideal, but one imperfect workaround to this issue – especially if your needs are simple – is to only ever create one price for any given currency and subscription period with a unit cost of 1.

It's a lot less common nowadays but years ago it was how many integrations were built when everything was still on the Price Plan API. It made donations forms especially easy, though it made for awkward Invoices and email receipts overall.

@TheBeardedRaspberry
Copy link

I just created hundreds of test prices by error in test mode and wanted to delete them after, only to get an error message and finding this issue. Not being able to delete TEST data is counter productive and insanely frustrating. I tried archiving the related products, but it does not archive the related prices and they still come up when I search for prices with stripe.Price.search(), even though their related products are archived. Guess I'm going to loop over all these prices objects now to set active = false on them :/
Oh and the dashboard doesn't help, trying to delete products with hundreds of prices doesn't work. It deletes 5-6 prices, and produces an error.

My point is, this is a TEST mode. I made an error, and I'm trying to fix it, but I can't and it's frustrating.

@pm-bc
Copy link

pm-bc commented Jun 4, 2023

This really should not even be a continuing conversation - and I'd refrained from posting recently, but that post above from TheBeardedRaspberry irked my dander once again. On that note, if the folks at Stripe would slap themselves on their collective heads a few times and realize that ... it's friggin' test mode for goodness' sake! Let developers develop... it's TEST mode because you expect them to mess around and make mistakes, and it's COMMON-FRIGGIN-SENSE that you need to let us wipe prices to start with a clean slate. Unreal!

@bioworkflows
Copy link

bioworkflows commented Jun 12, 2023

With full respect to Stripe developers (I got plenty of help from them through Discord) I landed on this ticket because I was surprised to learn that I cannot remove prices created by our unit tests. The consequence of this is that the amount of test data increases with each run of our test suite which makes using the dashboard to debug our integration increasingly difficult.

Just to say I am supportive of removing everything in test mode.

@WoodyWoodster
Copy link

+1 on making this feature a reality. Would be a huge time and cost saver if we could do this programmatically instead of through the dashboard.

@MilovanTomasevic
Copy link

I've created an automation script that simplifies the process of deleting archived products on the Stripe dashboard. This script uses Selenium in the background to perform the task seamlessly, saving valuable time during development and testing.

To use this solution, follow these steps:

  1. Clone the repository: Stripe Product Deletion Automation

  2. Install Selenium: pip install selenium

  3. Open the main.py file and provide your Stripe login credentials:

    USER_EMAIL = "ENTER_EMAIL"
    USER_PASSWORD = "ENTER_PASSWORD"
  4. Run the script: python main.py

The script will log in to your Stripe account and take care of deleting archived products. Enjoy the time saved!

@cafalchio
Copy link

Should have a price and product delete in the test API.

@MilovanTomasevic
Copy link

Should have a price and product delete in the test API.

With that current, first version, I deleted hundreds of my products that had multiple prices.

@woodsjd-cr
Copy link

woodsjd-cr commented Sep 13, 2023

I believe its possible to refactor your test setup so that you can simply archive and unarchive products and price objects.

Try:

  • create a function such as 'findOrCreateProduct' which will use the stripe API to check if the product already exists. And if not, create it. If the product exists, then unarchive it, along with it's archived price objects
  • create product with a product id you determine e.g. prod_TEST000001 then dynamically increase this with the number of tests you will run
  • create price objects and link them to the product just created
  • then for teardown, query price objects by passing in the product id to the api. Archive the price objects. Then lastly, archive the products

This should mean you dont continue adding to the 'archived' storage, and just archive/unarchive data already stored.

NOTE: I have not yet tried this, but it is the direction I'm going to try and take

@ginjo
Copy link

ginjo commented Sep 28, 2023

Yet another developer here who just stumbled on this issue after creating a whole lot of test products/prices. Very frustrating. I don't understand why it's such a problem to give us a soft delete in the API, with an option to include these inactive records in queries, if we so choose. Then Stripe can keep the data for eternity, and developers won't be bothered by it.

@made2591
Copy link

Following, the same issues above, I also wondered for a while "Would it be safe to launch this bulk creation, how can I clean up everything?" then I did it... and apparently I was wrong :( anyway in my case I don't have thousands of prices/products, still... frustrating

@mdiazr2000
Copy link

We are now in 2023, actually I can delete one product with its price through the dashboard but using the API when I try to remove the Product it says that there is a price related to it so it is not possible to erase it. It is necessary that exists a consistency between the API and what we can do using the Dashboard. I think that if using the Dashboard delete option I can delete one product I must have the same possibility using the API, please fix this as soon as possible, or give some consistency in the behavior of both API and Dashboard.

@pyrotank41
Copy link

It's 2024, and you cannot delete price from the api yet? I am using python and I am still getting the error "stripe._error.InvalidRequestError: Request req_fn450vi6oyjYpH: This product cannot be deleted because it has one or more user-created prices."

@gkuga
Copy link

gkuga commented Apr 21, 2024

I tried to delete the seed data mistakenly created in test mode.
Test mode is helpful for development, thank you, but couldn't find the price delete API, and discovered this issue.
I'm using nodejs, and there is a similar issue, so I'll link it.
stripe/stripe-node#916
I'll delete those through the Web UI for now, but I'd like an API for it.

@aaaaalec
Copy link

Please add this feature. If I can seed thousands of prices in an instant, I should be able to delete them just as fast. "Archived" should be reserved for unused novel prices, not the numerous clones that I have erroneously generated. Thanks

@jcroucher
Copy link

jcroucher commented Aug 8, 2024

This is a must. I have been tasked with cleaning up a Stripe account that got compromised.
The persons who compromised the account created 230,000 products while they were there, just for fun.

Clicking the "..." -> "Delete Product" -> "Delete Product" 230,000 times is not going to cut it.
I have had to write a chrome extension.

Also saying nothing should be deleted for "historical purposes" is not a great response either when it was all created by bad actors. Even a soft delete would be fine.

@n8vision
Copy link

I created an invoice and by mistake added a new price. I deleted the invoice draft. Now I'm stuck with a price which, though archived, still shows up in my list of prices for this product (why) and allows to be set as the default price (why) and I can't delete it because it says there's an attached invoice, but there isn't because I deleted that draft invoice (why). It's 2024. Thx.

Screenshot 2024-08-26 at 12 16 43 PM

@corydambach
Copy link

corydambach commented Sep 11, 2024

This is pretty disappointing, while I'm developing my workflow has been: 1. create my db 2. reseed it with some test data, 3. run tests and fix until I break something really bad 4. wipe the db and goto step 1. To do step 2 I have to make calls to my stripe dev sandbox to get the keys for the products and prices I create, as a result I have created dozens if not hundreds of prices and products on a test connected account (which is no big deal really), but what is the recommended workflow?

What's the point of not being able to trivially wipe a test environment?
It'd be even better to be able to snapshot my test environment in a certain state and roll back to it with an API call, but now I'm dreaming.

@raad-altaie
Copy link

Will this feature request ever be implemented?
It's a nightmare to manage prices with hundreds of archived prices and no option to search or sort. What a mess!
At the very least, there should be an option to soft delete or hide archived prices.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests