I\'m setting up a simple \'buy now\' transaction from a website with these major steps:
For a typical e-commerce site, yes you can -- it's fairly reliable. If nuclear reactors will melt down and people will die, then no you can't -- I've seen problems with it, but very infrequently.
I have not relied solely on IPN to do this, but PayPal will log failures to contact your server if it fails and is supposed to retry later, although I only ever had failures in development and never verified the retry. I just trust them on this one.
As the designer and administrator of a system that has processed over 600,000 PayPal payments in the last three years - relying exclusively on IPN will allow some errors to slip through the cracks.
Real data:
Total transactions No IPN Invalid IPN Duplicate IPN year 1 170,000 + 2 101 0 year 2 205,000 + 54 15 3 year 3 230,000 + 20 24 13
Fortunately, our system is structured with PDT (Payment Data Transfer) as a 'backup' so we didn't lose any transaction data or have unhappy customers. Note: PDT can't be relied upon exclusively either - in fact, early this year, there was a major problem with the reliability of PDT returns.
The most common 'invalid' IPN returns are an HTML error page or truncated results ... I can provide samples if desired.
The best choice is a combination of both IPN and PDT (with your 'cart' data stored in your DB as you are). Either the IPN processs or the PDT process can create the transaction (and delete the 'cart' data record in the DB). The second process to arrive will then not have a 'cart' entry from which to record a transaction.
NOTE: - as you noted in your final solution to use a custom field - be aware there is a length limitation to the custom field and it can be truncated upon being returned to you.
I have developed a number of eCommerce sites, and in practice you always want to record what you can in case of any 'accidents'. You own data is probably more informative.
Like you said, yes you can do this, but I would suggest that it is not a great idea.
It's important to do a 2 way validation like you have.
You save the order info (total, quantity) before the user leaves your system towards paypal. When ipn come back you validate the request (it must be from paypal ip or whatever), you validate that it's a successful transaction then your step 2 enters the scene. You validate if the total returned from paypal ipn is the same with the total that was saved before the user left (Paypal sometime may return partial payments, the user may grab the post data and do his own post from a modified html with a lower total
set). Step 2 should also store the user_id of the buyer so you must compare that too.
here's a sample layer (no programming language just a dummy code):
if request comes from paypal:
# query the order
if order.total == request.total && order.user_id == request.custom:
payment may come in...