Authorize.Net API questions and help with your payment integration.
Authorize.Net API questions and help with your payment integration.
11-29-2016 04:24 PM
I coded a SIM solution over 10 years ago, and it's been working fine for many clients. But I now need to add recurring charge capability. I desperately want to avoid any PCI requirements, i.e. I never want to see cc#s.
I think I see the solution after digging through the API doc. But I'm having trouble with the big-picture flow. Please bear with me on this. I have many years of career coding experience. But I need a bit of clarification and validation to make sure I am correct in my understanding of how all the piece-parts fit in the overall process.
The first thing I need is to validate that I can indeed do what I want to do, which is:
Assuming the above is possible, which from what I can tell, it apparently is.... I don't understand the 'createCustomerProfileRequest'. It says the cc# is 'required' for that API. But it says I have to call that API to get a profileId to be used to submit the form to capture the cc# (???). Is it actually ok to submit the createCustomerProfileRequest API without a cc#? Or am I totally missing something here?
Once I get past that hurdle above, can you verify my understanding that now I can simply issue a charge on that profile at any time using the API?
How close am I to correct? Again, I'm a professional code developer. So we can talk as technical as necessary.
Thanks so much for any info you can provide.
11-30-2016 10:35 AM
TL;DR answer: In your createCustomerProfileRequest, don’t send a paymentProfiles element and make sure that validationMode = “none”
Long answer: You've hit on a couple of points of confusion that many developers run into, namely how all of our pieces and features fit together, and which piece to use if you’re looking for a particular processing scenario. We’ve put a lot of effort into adding new features and new forms of integration, but with so many possibilities it’s not always clear what to choose for your specific case.
In the future, we’ll be putting a lot of effort into telling a clearer story to our developer partners, but in the meantime, let me at least clarify a few of the things that you’re seeing.
Older Authorize.Net technologies – We have a few technologies like SIM (Payment Form) that have been around for a while and still work fine. If you have an existing solution using SIM, there’s no immediate need to change things. However, if you want to add new functionality like recurring, you’ll look to adapt to something new because we haven’t added those new functionalities to SIM (as you’ve already found).
Again, no current need to move away from SIM if it does what you need. However, it will be deprecated and then eventually removed. We never deprecate a technology without suitable replacements in place and never remove anything without plenty of notice, so you’ll be fine with SIM for quite some time. For this reason, though, we generally don’t recommend anyone use SIM for a new project if there’s some other Authorize.Net technology they can use instead.
Current Authorize.Net technologies – Again, while stuff like SIM is still supported, future features and development effort are centered around the main Authorize.Net API. This is a server-to-server API, so in cases where a browser needs to talk directly to Authorize.Net to submit credit card details or other sensitive data, we’ve extended the API with what we call the Accept suite of functionality. Using one of the Accept products, you can get the cardholder’s information directly to Authorize.Net without having to handle it yourself.
For one-off transactions where you previously might have used SIM, we have the Accept.js library, allowing you to build your own form and have the credit card data from the form sent directly to Authorize.Net. Authorize.Net returns a payment “nonce”, a one-time token that’s submitted with the rest of the transaction processing in place of the payment data.
For recurring transactions, we already have the ability the charge a card periodically without sending the card data once the card information is stored on our server. However, to get the card information on our server without having to touch it yourself, we’ve got the Accept Customer solution that provides a hosted form the cardholder can interact with to submit card data to be integrated into their stored profiles at Authorize.Net.
Your case – Details on how to use that hosted form are listed under “Using the Accept Customer Hosted Form” at http://developer.authorize.net/api/reference/features/customer_profiles.html. Sounds like you’re with me so far, but since a new profile must be created before calling the form, how do you create one without payment information?
Payment information is something you can include in a profile creation request, but is absolutely not required. If you see any documentation that indicates otherwise, please let me know. What you want to do to send the creation request without payment data is remove all of the paymentProfiles element and all of its sub-elements.
If you submit the request without a paymentProfiles element, but with validationMode set to “testMode” or “liveMode”, you’ll get an error. That’s because you’re asking the API to validate the payment info you’re sending, but not actually sending any payment info. If you switch validationMode to “none”, everything works and you get a profile ID that you can use to request the hosted form.
The API reference is a little confusing with what it says about the use of validationMode = “none”, so I’m working on a change there to make it clear that that’s an appropriate case when making a profile without payment info. I’m also requesting a few other little documentation changes based on your issue to try to make the flow a little more obvious. That said, we’re always looking for feedback on how we can make things clearer, so if you have any other points you were confused on, let me know.
Hope this helps!
11-30-2016 02:58 PM
Wow, Aaron... thank you so much for the detailed response. SIM has been my friend for years, and I intend to keep using it for all of my clients that can use it for as long as possible. But the one client that needs recurring has forced me to branch into new areas.
I think I've got a pretty good idea of the flow now. Tell me if this is in error:
One time per customer as long as cc info is good:
1) CreateCustomerProfileRequest (no payment info; validate = none)
2) GetAcceptCustomerProfilePage (returns token)
3) Create HTML page form with hidden token field using returned token.
4) Display the resulting hosted page to customer
4) Customer enters cc info on hosted form and presses 'submit' or 'save' or something
Each time I'm ready to submit a charge:
I assume no validation of the cc info occurs until I submit a charge. So I must have a way to allow the user to go back in and change or correct the cc info if the payment is rejected, correct?
Thanks again fo the info. I think this is doable... :-)
11-30-2016 03:41 PM
Your basic flow is correct as outlined with the following clarifications:
If any of that's still not 100% clear, let me know.
11-30-2016 08:21 PM
Closing in on it... I now have the first steps coded and tested, and I'm getting a token back. Haven't actually sent the html request yet for the hosted page.
I understand what you are saying about not needing to get the payment profile each time. But what is the preferred way to get it the first time? Once I turn control over to the hosted form, I don't know if the user completed the cc info and submitted the form or walked away from the form, right? Is there some sort of callback (i.e. like SIM) to tell me that a profile has been added? (That may be in the docs.... I haven't really gotten that far yet... sorry). I guess the first time I need to charge, I can get all profiles and see if one exists, then save it off for future use (??). Is there a 'proper' way to do this?
Basically I'd like to get the profile created and make the first charge on it immediately. Then set up my own chron schedule to wake up after a prescribed number of days and charge again. Once I get the profileId, that seems straightforward. Just not sure how to know that the profile creation has indeed successfully occurred since I'm not hosting that page.
11-30-2016 08:35 PM
I forgot to mention the API name confusion you brought up about GetHostedProfilePageRequest vs. GetAcceptCustomerProfilePage. I'm using the Java samples. There is a Java class in the samples package for each of the APIs (which is very helpful, by the way....thank you!). For the most part, it appears that the Java class names are the same as the API. However, for the API in question, there is a "GetAccept..." java class, but no "GetHostedProf..." java class. The "GetAccept..." class uses GetHostedProfilePageController inside. So I'm assuming it's the one I should be using. I don't really care about the name of the class. I just want to be sure I'm using the right one. Is this just an inconsistency in the naming of the classes in the java sample package? (I did get a token back from this class).
12-01-2016 09:51 AM
Yeah, I see your concern. When you get the token, there's a hostedProfileReturnUrl parameter that you can pass. The customer gets a link to return to that URL, but following that URL doesn't give you any status. It's not a full form post back to your server of the profile details or anything.
So, yes, in this scenario, you have to query the profile to see what payment profiles may have been added.
One thing you could to is to use that URL to signal to your server that the customer is done so you know to go query the profile to look for changes. You could pass a URL like https://yourserver.com/profiledone?customer_id, so that when that URL gets hit, you know to go query the profile. That can work, but it's imperfect, because even though the customer got to the proper URL, you don't know if they actually updated the profile. Nor does it handle the situation where the customer updates their profile and just closes the browser. This is definitely an area where we can look at better notification in the future.
Otherwise, the only thing you'll really know for sure is the ID of the customer profile, meaning that in your case, you'd probably have to always query the customer profile to list all the payment profiles at that first transaction. You'll have to do that upon confirmation that the customer has returned, but then also figure out how to handle possible customer abandonment during the profile edit process.
Given these issues now that we've been talking about it a while, there's definitely some cases where it is a good idea to always query for all of the payment profiles associated with a given customer profile before charging just to make sure that what you're expecting to be there is actually there and that something hasn't changed. It's especially true if you have a function to allow customers to maintain/change their payment profiles and you later aren't 100% sure that you've stored the right payment profile ID to charge for future transactions.
With regards to timed subscriptions, I just want to make sure you know that we also offer that functionality on our side that ties into the customer profiles. If you want to manage that on your side, that's fine too, but I just want to make sure you know what else is on offer. Details are at http://developer.authorize.net/api/reference/features/recurring_billing.html
12-01-2016 10:00 AM
No worries, you've got the right class.
As far as I know, all of the Java class names match the API category names in our API reference. In the API, almost all of the actual calls are constructed from the names of the categories in the API (and thus the Java classes), but that "getHostedProfilePage..." is one notable exception that I feel compelled to point out to avoid confusion. Of course my pointing it out sometimes causes its own confusion...
12-01-2016 10:14 AM
Update! Breaking News!
When I said, "This is definitely an area where we can look at better notification in the future", that was a coy reference to our support for Webhooks, which I knew was coming but hadn't yet been officially announced. Sure enough, less than 30 minutes after I posted this, the official announcement went out.
So now, instead of trying to hack the return URL or anything, I'd strongly suggest looking into Webhooks as a way to receive notification every time a profile is created or updated. Check it out here: