Understanding and Using Ubercart’s Payment API

Ubercart has a fairly straightforward API for processing and logging payments that is quite similar in both the 1.x and 2.x branches. As a developer, you may run into a situation where you need to make manual note of external payments or trigger the automatic processing of payments based on your business rules. In Ubercart, there is a difference between processing a payment with the function uc_payment_process() and just recording a payment with the function uc_payment_enter(). To explain the difference, you should first understand a few concepts related to the payment system in Ubercart and how payment data is displayed to customers and administrators. After covering the terms and concepts, a full description of both functions mentioned above will be given followed by a section on using the API to process credit card transactions in your own code.

Ubercart Payment Terms and Concepts

First, Ubercart uses the term payment method to refer to a single method of payment that depends on similar customer supplied information or administrator defined instructions. For example, the credit card payment method defined by the related module handles the collection and secure handling of credit card information supplied by the customer during checkout. Ubercart’s Payment Method Pack module defines a check or money order payment method that adds instructions for the customer on the checkout screen.

Second, Ubercart uses the term payment gateway to refer to a third party application that provides a web service allowing you to process payments for a particular payment method. For example, Ubercart ships with modules that define Authorize.Net and CyberSource as gateways for processing credit card payments. Ubercart does not require a payment method to use a payment gateway for processing payments. The core PayPal module defines a payment method for PayPal Website Payments Standard that simply redirects the user to PayPal at the end of checkout for payment submission. Our contributed UC eCheck.Net module provides an eCheck.Net payment method that collects checking account information on the checkout form and acts as a payment gateway module by processing the payment upon submission, though it could theoretically be divided into a generic eCheck payment method module and a specific eCheck.Net payment gateway module for processing eCheck payments.

When a payment is made in Ubercart, the transaction data is stored in the database table uc_payment_receipts. Each receipt includes the order ID, the payment method used for the payment, the amount of the payment, and some other related meta data. Transaction receipts are visible on an order’s Payment tab for users with appropriate permission. When an order is loaded, the order’s total is available in the order object as $order->order_total. To find out the current balance of an order (the order total minus any payments received for the order), you must use the function uc_payment_balance().

Knowing the types of payment modules you have used to configure payments on your Ubercart site is important when considering manual payments in your custom code. If you want to process a payment for a payment method that depends on a payment gateway (at this point, only the credit card method), you should use the function uc_payment_process(). This will automatically determine the payment gateway to use for processing the payment, and upon success will use the uc_payment_enter() function to record a transaction receipt in the database.

If you just want to make note of a payment processed either through some external system or captured using a payment method that does not depend on payment gateways, you can use the uc_payment_enter() function directly. This is functionally equivalent to an administrator browsing to an order’s Payment tab and entering a payment using the form on that page.

For either of these functions, you’ll need to know the order ID, the amount of the payment, and the ID of the payment method you’re using. Every payment method has a unique string ID that you can find in its module’s implementation of hook_payment_method(). The order and nature of other parameters for these functions will be explained below.

uc_payment_enter()

<?php
function uc_payment_enter($order_id, $method, $amount, $uid, $data, $comment) { }
?>

As was noted above, this function is used to enter a payment for an order. Specifically, the function takes care of building the query to insert the row into the uc_payment_receipts table. If payment logging is enabled, it will also log the payment action to an order’s Log tab. The parameters for the function are fairly straightforward:

  • $order_id = the ID of the order for which the payment is being entered.
  • $method = the ID of the payment method, like ‘check’ or ‘paypal_wps.’
  • $amount = the dollar amount of the payment.
  • $uid = the user ID to log with the payment, generally the ID of the user entering the payment. You may specify 0 if there isn’t an immediately applicable user.
  • $data = a string or array of data pertaining to the payment that you want to store with the receipt, like a transaction ID.
  • $comment = a string to be displayed in the Comments column of the table on the order’s Payments tab.

As has been noted above, entering a payment with this function does not actually process any transaction. It is merely a record of a transaction that has already taken place, whether it happened through a payment gateway or by your store physically depositing a check at the bank that was mailed in by the customer.

When a payment is entered through this function, the Conditional Actions trigger A payment gets entered for an order is pulled. It receives the order object as an argument, so you can do any additional order processing necessary based on order values or the resultant order balance. For example, core Ubercart ships with two default predicates that get evaluated when this trigger is pulled:

  • Update order status on full payment – when a payment is entered, if the order balance is less than or equal to $0.00 and the order status is not already Payment received, the order status will be updated to Payment received.
  • Update order status upon checkout completion with full payment – when a payment is entered, if the order balance is less than or equal to $0.00 and the order is not shippable, the order status will be updated to Completed.

The latter predicate is used to facilitate the automatic processing of role promotion and file download orders where it makes sense for these orders to immediately be marked as Completed when payment is received for the order. Either one of these may be disabled or modified to your liking depending on your business rules.

uc_payment_process()

<?php
function uc_payment_process($method, $order_id, $amount, $data = NULL, $default = FALSE, $selected = NULL, $redirect = TRUE) { }
?>

As was noted above, this function should be used when you want to actually process a payment through a payment method’s payment gateway. The current gateway being used for a payment method is configured in the Payment method settings form. The appropriate data will be passed to the payment gateway function based on the parameters you pass to uc_payment_process(), and this function will automatically enter the payment through uc_payment_enter() upon success or log it as a failure. Currently, this function is only used in core for the credit card payment method.

The parameters for this function are as follows:

  • $method = the ID of the payment method, like ‘credit_card’.
  • $order_id = the ID of the order for which the payment is being entered.
  • $amount = the dollar amount of the payment.
  • $data = An array of data passed to the payment gateway module used for processing the payment.
  • $default = TRUE or FALSE to indicate we're forcing the use of the default gateway for the specified payment method. When TRUE, admin messages related to the payment will be hidden from display so customers don't see them.
  • $selected = when specified, the ID of a payment gateway to use to process the payment; normally comes from the payment gateway select form.
  • $redirect = TRUE or FALSE to indicate whether or not to redirect back to the admin order view page for the order referenced in $order_id.

The payment gateway select form is available when you want administrators to be able to select from multiple installed payment gateways for a payment method, but at this point it is unused in core. Due to limitations we were unable to fix in time for a release, the default payment gateway specified on the Payment method settings form will always be used. If you want to silently process a payment or enter multiple payments during something like a cron run, be sure to set the $redirect to FALSE.

Knowing what $data to pass to uc_payment_process() depends on a knowledge of the particular payment method and what it expects to send to its payment gateway callbacks. For the credit card payment method, this generally includes at least the transaction type and, depending on the type, an authorization ID or reference ID. You can view an example of how this array is built by referring to the credit card terminal form’s submit handler. Look for the 40 line switch() statement in uc_credit.admin.inc in the function uc_credit_terminal_form_submit(). If you wanted to manually process a credit card payment for an order through the API, you might use something like the following:

<?php
uc_payment_process
(‘credit’, 42, 100, array(‘txn_type’ => UC_CREDIT_AUTH_CAPTURE), TRUE, NULL, FALSE);
?>

This will process a $100 payment for order 42 using the credit card payment method. The data passed to the default payment gateway for the method will indicate that this is an authorization + capture transaction, which means the payment will be processed against the customer’s credit card information immediately if the funds are available. If this payment succeeds, a receipt for the transaction will be entered in the uc_payment_receipts table. There will be no redirect once this payment has processed.

Credit Card Payments in Ubercart

The credit card system in Ubercart is quite complex and was hindered at one point from developing further by our release cycle. As such, you’ll find that authorization IDs and reference IDs are stored in the order object in the $order->data array instead of a unique table. If you want to process prior authorization captures or reference transactions, you must locate the appropriate ID in this data array. Again, you may refer to the submit handler for the credit card terminal form for example code. In the case of that form, the ID is selected from the form based on all the available IDs in the order’s data array.

Furthermore, if you load an order object through the API, it will not have credit card data in it. One of the confusing things for developers has been when and where credit card data is available. During checkout, the data is located in the $order->payment_details array, but after checkout, some card data will be truncated for security reasons. Even if you were to edit the order later and attempt to add the credit card information back in, you would find that the data is again truncated when saved for security reasons. To manually process credit card payments through the user interface after an order has been created, you have to use the credit card terminal form accessed through the Process card button on an order’s payment pane.

This means that if you want to manually process credit card payments, you either need to add the credit card payment details to the order object yourself or solely rely on this function for prior authorization captures and reference transactions. In either of these instances, payment gateways use the ID you supply to locate the proper credit card data stored in their system for processing the payment. Make sure that you pass an appropriate data array, basing your array on the examples found in the credit card terminal form’s submit handler.

Conclusion

There is certainly more that could be said, but hopefully this provides a helpful starting point for people writing custom payment integrations for Ubercart sites. We’ll cover defining new payment methods and payment gateways elsewhere, but if you want some simple examples, refer to the UC eCheck.Net module for an example of a payment method and UC NAB Transact for a simple example of a payment gateway. Even as I type this, I’m seeing areas for improvement in future iterations of this API (like unifying the order of the parameters for uc_payment_process() and uc_payment_enter()), but please feel free to note your own suggestions or questions in the comments below.

Ryan's picture
Ryan Szrama

Ryan got his start in web development through an online sales company based in Louisville, KY, his home of over 10 years. It was there that he nursed Ubercart through its infancy to its use on over 20,000 websites as the Project Lead and community face of the project. Ryan joined Commerce Guys in 2009 and continued to lead Ubercart until branching out into Drupal Commerce, a new initiative focusing on empowering users to build e-commerce sites with the best new features that Drupal 7 has to offer. He focuses most of his time developing the code base, growing the community of contributors to the project, and training new users online and at community events.

Comments

Thanks for this article, it

Thanks for this article, it seems like a good starting point for my payment gateway development