====== Using Foxy Without the Cart ====== **Skill Level:** Advanced. There are a few situations where FoxyCart's "cart" functionality isn't needed. Though an uncommon situation, some examples include: * Integrations where a persistent cart already exists, and where Foxy is replacing just the checkout flow (to offload PCI compliance burdens, most frequently). * Custom situations where a cart doesn't exist, but where custom validation or other advanced requirements may require your own application logic in front of the Foxy-powered cart. * Sites or services where products are configured at the time of purchase, and a customer shouldn't ever be able to directly interact with the cart. (Note that this is generally possible in a simpler way than outlined on this page.) Luckily, Foxy is flexible enough to handle even some of the most customized requirements you could throw at it. On this page, we'll discuss the basic approach you might take for integrations like this. First, though, a few important notes. ==== The Cart: Interaction versus Underlying Data ==== When we use the term "cart", we can mean two different things: - The visual display of the cart that a customer usually sees. This would include things like the names, details, images, prices, and quantities of the items a customer is purchasing. - The underlying data behind the visual display. Though you can avoid the first, Foxy will always require the "cart" to exist for a transaction. This ensures Foxy can provide all of these details to the payment systems (ie. Authorize.net, Stripe, PayPal, Amazon), and also that taxes and other functionality works as expected. In other words, you can't simply tell Foxy "Charge this customer $100". Instead, you must supply //what// constitutes that $100 charge. Note that you can entirely bypass the cart (and take customers straight to the checkout) //without// doing anything on this page. Simply use the ''cart=checkout'' parameter described [[.:cheat_sheet|on the cheat sheet]] to skip the cart step entirely. ==== The Checkout ==== Though you can self-host a custom cart if desired, you must use Foxy's hosted checkout (located at ''/checkout'' at your custom Foxy domain). This ensures the bulk of PCI compliance is shifted from you to us. ===== Serverside Cart Creation and Interaction ===== ==== An Overview ==== A normal Foxy integration would look like this: - Your website has "add to cart" or "buy now" (or "donate now", etc.) buttons (links or forms). These buttons are ''a'' or ''form'' elements pointing to the ''/cart'' endpoint of your FoxyCart account. - A customer clicks one of those buttons. The browser submits a ''GET'' or ''POST'' request to the Foxy ''/cart'' endpoint. The cart is then displayed. By default, this would be the "sidecart" that slides in from the right, but it could also direct the customer to a new webpage showing only the cart, or it could take the customer directly to the checkout (which displays the cart in the right column). - The customer lands on the Foxy-hosted checkout page. The customer completes the page and clicks to submit their payment. - The payment processes successfully and lands on the Foxy-hosted receipt page, showing what they just purchased and relevant transaction IDs. Let's imagine that you've already got your own cart functionality, however, and your "add to cart" buttons are already pointing to your own system. You want to continue using that functionality, but to have Foxy take over at the checkout portion. Here's how your integration would differ from the approach above: - Your website's "add to cart" buttons point to your own system, and not to your store's ''/cart'' endpoint. - Any cart that is displayed (prior to the checkout) is entirely handled by your system. - When the customer indicates they'd like to pay, your system… - Creates a cart in Foxy (using the Foxy API), based on the items in your own system's cart for that user. - Redirects the customer to the ''/checkout'' URL with the appropriate session ID, and optionally with [[.:sso|a SSO token]] if the customer is already authenticated. - Once the customer completes the checkout on the Foxy-hosted checkout page, the customer can… * Land on the Foxy-hosted ''/receipt'', or * The Foxy-hosted ''/receipt'' can immediately redirect the customer to a URI of your choosing, optionally with a "reverse" (or outgoing) [[.:sso#reverse_ssologging_a_customer_into_your_own_site_from_foxycart|SSO token]]. * Your system can optionally create or sync [[.:customers|the customer's account]] so their info entered in Foxy is up to date with the info in your system (including their hashed password). There are a few moving pieces here: the cart; incoming SSO (single sign-on); outgoing/reverse SSO; and synching customer records. We'll cover each below. ==== Using the API to Create a Cart ==== Foxy provides two different methods of interacting with the cart. The ''/cart'' endpoint, and the [[https://api.foxycart.com/|hypermedia API]]. === The ''/cart'' Endpoint === The most straightforward approach is to use the same ''/cart'' endpoint that the clientside requests hit, using the ''output=json'' parameter. There is no authentication with this approach (though you can use the [[.:hmac_validation|link/form signing functionality]] to lock things down), so this approach is generally going to be easier to work with for most users. This approach works just like normal cart requests from the client, except with the ''json'' output flag, Foxy will respond with valid JSON that's easy for you to parse and act upon. For example, if you load up this URI (replace the ''YOURDOMAIN'' as appropriate, and disable the [[.:hmac_validation|hmac link/form signing]] in your store settings to test)… curl https://YOURDOMAIN.foxycart.com/cart\?name\=Cool%20Example\&price\=10\&color\=red\&code\=sku123\&output\=json (Alternately, you could do a ''POST'' to your ''/cart'' endpoint, which may be easier if you're doing serverside interactions.) You'll see JSON like this: {"locale_info":{"decimal_point":".","thousands_sep":"","int_curr_symbol":"USD ","currency_symbol":"$","mon_decimal_point":".","mon_thousands_sep":",","positive_sign":"","negative_sign":"-","int_frac_digits":2,"frac_digits":2,"p_cs_precedes":1,"p_sep_by_space":0,"n_cs_precedes":1,"n_sep_by_space":0,"p_sign_posn":1,"n_sign_posn":1,"grouping":[],"mon_grouping":[3,3],"int_p_sep_by_space":1,"int_n_sep_by_space":1},"locale_code":"en_US","weight_uom":"LBS","context":"cart","store_id":41795,"transaction_id":1109984022,"items":[{"item_number":1,"shipto":"","id":71966542,"name":"Cool Example" The above response is truncated, but the full response includes everything necessary to understand and work with the cart. One of the most important elements of the response is the ''session_id'' value. If you’d like to modify that cart, you’ll need to pass through the session ID (like ''&fcsid=abc123xyzetc''). FoxyCart will create a new session if no ''fcsid'' value is passed through with the request. === The Hypermedia API === //**__Experimental Functionality__**// Though creating a cart via the hypermedia API is supported (and being used in production by some of our users), please drop us a note if you proceed with this approach, and if you encounter anything unexpected. Retrieving and setting shipping rates, in particular, isn't currently supported by the hypermedia API, so you'll need to use non-hAPI approaches (described below) in certain situations. If you're building a deeper integration, you may already be working with our [[https://api.foxycart.com/|Hypermedia REST API]]. For the purposes of this page, we'll assume basic working knowledge of the hAPI (including authentication via OAuth 2.0 and how to navigate using the hypermedia link relationships). This hAPI approach provides considerably more functionality, as well as a consistent interface for all things related to your Foxy account, and can replicate the above ''/cart'' endpoint approach, albeit with a few more steps. The basic idea is to ''POST'' to the ''/carts'' resource URI (obtained from the hypermedia relations) for your store. Note that you can ''PUT'' an entire cart by taking the approach outlined in the "Modifiable Embedded Resources" section of [[https://api.foxycart.com/rels/carts|the ''carts'' resource documentation]]. Note that with this approach, you //will not// receive an ''fcsid'' session ID. In order to create a session associated with a cart, you'll need to use the [[https://api.foxycart.com/rels/create_session|''create_session'' link relation]] from the cart you've created. That will get you the ''fcsid'' value you'll use later. Regardless of the approach you take, you'll end up with a cart (ie. a collection of items). Once it's as it should be, the next step is getting the customer to pay for it. ==== Passing the Customer to the Checkout ==== === Session Handling === The next step is to send the customer to the checkout to pay for the cart you've created. This is straightforward. Simply send the user (via a ''Location'' header or your preferred method) to ''https://YOURDOMAIN.foxycart.com/cart?cart=checkout&fcsid=YOUR_FCSID_VALUE_HERE''. === Single Sign-On (Incoming) === In situations where your customer is already authenticated in your system, you'll want to use our [[.:sso|Single Sign-On functionality]], so the user doesn't need to login again. If SSO is enabled for the store, a valid SSO auth token is required to load up the ''/checkout'' page. In the above ''cart=checkout'' example, the customer would then be redirected to your configured SSO endpoint URI. Your endpoint would then check the user's authentication (since your endpoint would generally be on the domain the user's logged in, so your endpoint could determine their logged-in status based on their cookies), and would generate the appropriate token and redirect the user back to a URL like this: /checkout?fc_auth_token=AUTH_TOKEN&fcsid=SESSION_ID&fc_customer_id=CUSTOMER_ID×tamp=TIMESTAMP These multiple redirections aren’t necessary in a "mostly serverside" situation, however. If you already know the user is authenticated and want to send them directly to the checkout, you can send them to the ''/checkout'' URI with the ''fc_auth_token'' right in it. (Note that before sending a user, you'd need to create that user in Foxy. This would be done with the hAPI, and could be done either on-demand right before the redirection to ''/checkout'' takes place, or ahead of time (batched, triggered by user creation or updates, etc.).) ==== Handling the Customer After the Transaction ==== === Default Behavior === By default, a successful checkout will land the user on a Foxy-hosted [[.:receipt|''/receipt'' page]], and will also trigger a [[.:transaction_xml_datafeed|webhook]] (which we often call a "datafeed"; way back when we named it, the term "webhook" wasn't the norm :). Though this receipt can be customized, for more advanced integrations like we're discussing here, it may not be sufficient. === Redirecting from the Receipt === If you'd like to redirect the customer to your own receipt, or perhaps to redirect them to another section of your site, you can easily do some conditional logic on the receipt to redirect the customer. There are a few possibilities here: * Empty the Foxy receipt template so it will //never// display anything, and will //always// redirect customers elsewhere. * Use the Foxy receipt for historical purposes (as it's linked to by default in the email receipt templates), but set logic to immediately redirect on the initial view. * Use the Foxy receipt without an immediate redirect, and allow an optional "Click here to continue…" to allow customers to continue to the next step. * Other ideas? Feel free to contact us if you'd like to explore another option. Let's assume the 2nd bullet there, so a customer who's just purchased something will be immediately redirected to another page. You'd add some code to your template config [[.:receipt#display_conditional_content|as outlined here]], using the ''first_receipt_display'' boolean check if you want to ensure the redirection //only// happens on the very first viewing of the receipt. === Single Sign-On (Outgoing) and User Synching === The final optional piece of the puzzle is outgoing SSO, so a customer (either brand new or returning) who's completed a transaction will be logged into your own system after their transaction. (This can be particularly useful for situations where customers are paying for access to content on your website, as they can go from the Foxy-powered checkout straight to the relevant section of your site, without needing to login again.) There are some examples of code on [[.:sso#outgoing_ssologging_a_customer_into_your_own_site_from_foxycart|the receipt documentation]], and if you're doing incoming SSO, it will be very familiar to you at this point. Note that though we don't support SAML by default, we can implement SAML for our Enterprise users. (Because of the complexities of synching users, it's not something that works "off the shelf", but it is doable either by us, or by you using an intermediary script to go from SAML to our own SSO approach.) ===== Shipping, Taxes, Coupons, and Other Considerations ===== For this section, we'll be using the ''/cart'' endpoint, not the hypermedia API. (This functionality will be added to the hAPI, but is currently unavailable there.) ==== Taxes ==== Taxes are applied automatically during the checkout process, but if you'd like to retrieve a tax estimate during your own checkout flow, you'd do the following: - Create the cart and session as outlined above. - Attach a postal code to the session. Do this via the browser and review the javascript requests and responses made for your particular account, but it'll look something like this: ''https://EXAMPLE.foxycart.com/v/2.0.0/api_json.php?city=San+Diego®ion=CA&postal_code=92106&country=US&ThisAction=SaveCartContactInfo&fcsid=XXX&store_id=XXX'' (where you'd replace the ''XXX'' and domain as appropriate). * There's also a ''GetAddressByPostalCode'' action that will retrieve possible cities based on an entered postal code, if you'd like to use that like the Foxy checkout, to do a bit of address validation. (This can help ensure more accurate tax rates.) - Retrieve the tax information with a request to ''https://EXAMPLE.foxycart.com/cart?fcsid=XXX&output=json''. Display it however you'd like. - **Note:** You may need to repeat the previous step after setting the shipping details for the transaction, as the tax value may change based on the shipping cost. ==== Shipping ==== Shipping is also handled on the checkout automatically, but there may be situations where you'd like to set the shipping details (method name and price) without user input. There are a few possibilities here. === Step 1: Adding the rate to the session === The basic idea involves a request like this: https://EXAMPLE.foxycart.com/v/2.0.0/api_json.php?shipping_address_name=YYY&shipping_service_id=XXX&shipping_service_description=UPS+Ground&total_shipping=16.65&total_future_shipping=0&ThisAction=SaveShippingServiceInfo&fcsid=XXX&store_id=XXX (Note that the ''YYY'' value is used for [[.:multiship|multiship addresses]], and will normally be left empty if you're not using multiple shipping addresses in a single transaction.) **Using Foxy's Built-In Shipping Functionality:** If you complete the steps above to get a tax, you'll notice the cart's JSON now contains a ''shipping_results'' node. You can use those values to submit back to the cart, passing through the values like the link above. Note that you can still use the [[.:shipping#custom_shipping_endpoint|custom shipping endpoint]] with this approach. **Using Arbitrary Shipping Amounts:** You can also pass through arbitrary shipping details, which may be preferable in certain situations. A few caveats: * The ''shipping_service_id'' should be an integer greater than 10000. * Signing requests: We are currently working to allow this approach to work with the "shipping rate signing" functionality enabled. Contact us for details. If you're going to use the Hypermedia API to push through the transaction programmatically at this point, you're done. If you're going to pass the customer on to the ''/checkout'' page to complete the transaction themselves, continue to Step 2. === Step 2: Handling the shipping on the checkout === This section will seem like extra work, and in many ways it is, but it ensures the integrity of the checkout. Even though you've already set the shipping rate you want, you'll need to do this again using the [[.:shipping#custom_shipping_endpoint|custom shipping endpoint]] functionality. If your endpoint returns the same details as you set in Step 1 above, the checkout will load with that shipping rate already selected and ready to go. (Note: If you're using [[.:sso|SSO (Single Sign On)]] and the user is authenticated, the rate may not be selected. Please contact us to discuss options with you so your users can avoid needing to select the shipping rate.) ==== Coupons ==== If you handle your own coupons or discounts within your system, you'll want to ensure those get passed through to Foxy appropriately. At present, Foxy doesn't allow passing through arbitrary discount/coupon amounts like it does shipping (above), so this is a bit more involved. - Calculate the appropriate discount in your system. Let's assume it's $10. - [[https://wiki.foxycart.com/v/2.0/shipping#custom_shipping_endpoint|Create a coupon code]] using the hAPI for that amount (with the appropriate other details like display name and such). - Add that coupon to the existing cart with a request like ''/cart?coupon=XXX'', where ''XXX'' is the coupon code as configured. A few notes: * You can remove coupons if necessary with a link like ''/cart?cart=remove_coupon&coupon_code_id=XXX&fcsid=XXX''. The respective ''coupon_code_id'' is available within the ''coupons'' node of the cart JSON for each coupon currently applied to the cart. * If you have discounting logic that fits with Foxy's functionality, we recommend piggybacking on that. For example, if you have quantity discounts, we'd recommend using Foxy's built-in logic rather than calculating a discount and creating a unique code per transaction. Similarly, if a coupon's discounting logic can be replicated in Foxy, you can create a single coupon and reuse it. ===== Putting It All Together ===== Please let us know if you have any questions about this approach. You can always reach out to [[http://www.foxycart.com/contact|our support email]]. For advanced integrations like this, however, we are only able to offer support to users on our API Premium or Single-Store Advanced plans.