Auth-fulfill-capture

This workflow allows you to authorize a charge outside of NetSuite and later capture the charge when a NetSuite Invoice is created. This is helpful for companies that use an eCommerce platform to collect order and use NetSuite to manage fulfillment.


This workflow is a great fit if you use NetSuite for order fulfillment, A/R collection, and customer service (refunds, returns, etc); but leverage another system (Shopify, SalesForce, etc) for order collection and payment authorization. In this workflow, your eCommerce system authorizes charges in Stripe, and SuiteSync captures the authorized charge.

For example, if you are a retailer who wants to capture a charge once the order has shipped from your warehouse, this solution is a great fit.

Here's an overview of this workflow:

  1. A charge in Stripe is authorized, but not captured
  2. A SalesOrder is created in NetSuite. The Stripe Charge ID is included on the SalesOrder.
  3. A Invoice is created from the SalesOrder. This normally happens once the order has been fulfilled.
  4. SuiteSync looks for NetSuite Invoices and captures the total amount due on the invoice.
  5. The CustomerPayment is automatically reconciled to the corresponding bank deposit. Processing fees are automatically recorded.
  6. Later on, if a CreditMemo is created from the Invoice, SuiteSync will create a refund in Stripe for the amount of the credit memo.

Key benefits of this flow:

  • Your CX team doesn't have to use Stripe to create refunds or manage the order flow.
  • Your technical team won't have to build a custom integration or manage getting several integration systems working together.
  • Your finance team will stop managing cash application, deposit reconciliation, and fee recording. This is completely automated and happens silently in the background.

Technical Overview

Your system is responsible for:

  1. Creating an authorized (uncaptured) Stripe charge. The payment method must be saved (by creating a Stripe customer) for the reauthorization to successfully occur in the case of an expired payment.
  2. Pushing an order to NetSuite, and adding the Stripe Charge ID to a custom field on the SalesOrder (more on this later). This is done by a NetSuite integration specific to your eCommerce application. There are pre-built integrations available for most eCommerce applications.
  3. Billing the SalesOrder by creating an Invoice

After the SalesOrder is billed, SuiteSync handles the rest of the process:

  1. SuiteSync inspects all open invoices that contain a Stripe Charge ID in the custom transaction field. When a charge is found, it is captured for the amount remaining on the invoice.
  2. If capture fails, a new charge is attempted to be created. If the new charge creation fails, a message is added to the invoice memo (more details on this process).
  3. If capture succeeds (or if a new charge is successfully created) a CustomerPayment is created and applied against the Invoice.
  4. The CustomerPayment is reconciled against the corresponding bank deposit using the standard transfer reconciliation flow

What is the Recommended NetSuite Order Workflow with Auth-capture?

NetSuite's order processing workflow is very powerful and allows you to customize the workflow depending on your business logic. For instance, shipments can have multiple stages, orders can be billed before they are shipped, etc.

Below is a recommended workflow for auth-capture based on the following assumptions:

  1. Sales orders need to be fulfilled, and the fulfillment process is tracked in NetSuite
  2. Sales orders are created before payment is collected (captured)
  3. Sales order should not be fulfilled until the payment has been successfully captured

Here's the approved workflow:

  1. Unapproved SalesOrders are created in NetSuite through an eCommerce integration, CSV import, etc.
  2. SalesOrders are approved by operations/fulfillment. Fraudulent orders are canceled before being approved.
  3. After a SalesOrder is approved, an Invoice for that SalesOrder is created.
  4. SuiteSync captures the charge associated with the NetSuite Invoice based on the invoice total.
  5. If capture succeeds, payment is applied against the invoice, marking it as paid.
  6. When a invoice is marked as paid, a shipment (item fulfillment) is created. The fulfillment team can watch a queue of "Pending Fulfillment" invoices create shipments or shipments can automatically be created.
  7. If capture fails, invoices remain unpaid, and the failure is indicated on the Invoice. The finance/collection team can watch the queue of unpaid invoices which failed to collect and initiate a collection process for that customer.
  8. If capture fails, an optional feature can be enabled that puts a credit hold on the associated customer. This enables your finance team to start a collection process based on this customer status.

Note that in most cases, anything that seems "manual" can be automated using a NetSuite workflow or SuiteScript.

To support this flow, you'll need to:

  1. Enable the "Invoice in Advance of Fulfillment" NetSuite feature. This enables you to bill a SalesOrder without fulfilling it.
  2. Enable the "Enforce Holds" NetSuite feature and the associated feature in SuiteSync.
  3. The process for "watching" the queues described above is dependent on your business and existing processes. The simplest way to watch the queues described is a NetSuite saved search, but workflows and SuiteScripts can be used to further automate this process.

Here's instructions on how to enable these features.

Implementation Guide

Here's how to use auth-capture in your application:

  1. Create a custom transaction body field in NetSuite called custbody_suitesync_authorization_code. We create this for you during the onboarding process (you can also create it yourself)
  2. When creating the NetSuite SalesOrder or Invoice set the custbody_suitesync_authorization_code field to the Stripe ID of the authorized charge. The Stripe ID starts with either ch_ or py_.
  3. The form used on the SalesOrder must create an Invoice in NetSuite. CashSales are not supported.
  4. If you have multiple subsidiaries, it's critical that the bank chosen connected to Stripe account is connected to the same subsidiaries as the NetSuite customers.
Can I partially capture a charge more than once?

If you partially ship orders you'll often create two invoices for each partial shipment.

Unfortunately, Stripe only allows a charge to be captured once. Learn more about this.

Although multiple captures are not supported, if the card used for the charge was stored, SuiteSync creates a new charge for the second invoice.

How does the customer hold integration work?

If a charge reauthorization is required when capturing the charge and the newly created charge fails, the customer can optionally be put on credit hold.

A reauthorization is required if the charge expires, and in a couple of other cases detailed below.

Are CustomerDeposits Supported?

Not in the auth-capture flow. They represent a successful pre-payment. Since charges are not successful until they are captured, a CustomerDeposit can only be created if payment is authorized and captured during checkout.

Note that it is possible to use auth-capture in conjunction with the standard ecommerce workflow.

Are CashSales Supported?

They aren't. Only Invoices coupled with CustomerPayments are supported in the auth-capture workflow. This is a technical limitation¬タヤif more expanded APIs are released in the future that allow us to support CashSales, we will.

To capture payment SuiteSync must:

  1. Know that the order amount is finalized/fulfilled
  2. Be able to retrieve the final total amount that should be captured. In some cases, the finalized order total may not equal the original authorization amount.

Both Invoices and CashSales contain this information.

However, CashSales represent both an Invoice and a CustomerPayment in a single record. There is no A/R accounting entry made when a CashSale is created and an entry is made directly to cash.

Stripe Charges are not captured immediately when the CashSale created. Instead, a notification is sent to SuiteSync to capture the charge when the CashSale is created. Since the capture operation is run asynchronously and may not always succeed (if the charge expired, for example), creating a CashSale would incorrectly represent the reality in your Stripe account: an entry should not be made to undeposited funds until the charge is successfully captured in Stripe.

Can I capture less than the authorized amount?

Yes. The "amount due" of the invoice is captured. If the amount is less than the original authorization, then the charge is only partially captured and the rest of the authorization is released to the customer.

If the amount due is larger than the original authorization amount than a new charge is created for the higher amount due.

Are Stripe Orders (Relay) supported?

Yes. However, if you are using Stripe Orders the workflow is completely different. Learn more here.

I'd like to create an authorization for more than 7 days. What are my options?

Often customers want to authorize a card for an order that is fulfilled more than seven days in the future (pre-orders are a great example here). If you capture a charge when the order is fulfilled, the authorization would expire.

There's not a clean way to hold an authorization over a long period of time—essentially creating a new authorization over and over when the old charge expires. Each bank (and each card network!) handles authorizations slightly differently. For example, if you continually reauthorize a charge it may not look the same to the customer (they may see multiple independent authorizations on their statement for a period of time) and it might work against your end goal.

For instance, if you'd like to create four authorizations for a 30 day pre-order, the 1-3 authorization may work just fine but depending on the timing on the underlying bank it's possible for the four charge to fail in part because of the 2nd or 3rd authorization.

Here's the recommended approach:

  1. Create a customer in Stripe and store the card information.
  2. Authorize a charge against the saved card
  3. When the order is ready to be shipped, charge the user saved card.
  4. Ship the product

The key difference here is it is important to setup your order workflow to only ship the order after the order has been paid in full.

How are failures handled?

Some failures simply cause a delay (if the NetSuite or Stripe API is down, for instance) and are handled automatically. Other failures cause additional information to be added to the NetSuite invoice but are resolved automatically as well.

However, there are some errors that cannot be recovered from automatically and require intervention on your end to resolve.

Authorized charge has expired

An authorized charge expires after 7 days. This authorization window cannot be changed.

If you create an Invoice in NetSuite after that 7-day period a new Stripe charge is created. The same card that was used for the original authorization is used for this new charge.

The new Stripe charge ID that is created is written to the "SuiteSync Authorization Code Field".

A note will be added to the memo indicating that a new charge was created because the original charge failed to capture. Here¬タルs what the memo will say: ¬タワSuiteSync: charge ch_123 failed to capture. New charge created."

Amount due exceeds original authorized amount

First, the authorized charge is deauthorized, releasing the funds back to the customer.

Next, a new charge is authorized and captured for the amount due on the invoice. A memo is added to the invoice indicating that a new charge was created Stripe: insufficient authorized funds on ch_123. New charge created. The new charge ID is added to the "SuiteSync Authorization Code" field.

Partially fulfilled orders with multiple invoices

If an order is partially fulfilled, two ItemFulfillments are created, which creates two separate invoices. Stripe only allows a single capture against an authorized charge.

When the first invoice is created, the charge is captured based on the "Amount Remaining" field on the first invoice.

When the second invoice is created, a new charge must be created. This reauthorization process works identically to if the original charge authorization expired. The "SuiteSync Authorization Code" field will be overwritten with the new Stripe charge ID. A new charge is only created when the SalesOrder that the invoice is created from is the same SalesOrder that the invoice associated with the charge where the capture was initiated.

A note will be added to the memo indicating that a new charge was created.

Reauthorization failure

In order to solve many of the above failure cases, a new charge needs to be created. The new charge uses the same card as the original charge.

However, this new charge is not guaranteed to succeed. Here are examples of a couple of instances where this charge could fail:

  • The saved card information was removed from the Stripe customer
  • The card was canceled
  • The card reported insufficient funds

If these (or any other errors) occur when creating the new charge, a memo is added to the invoice indicating Stripe: payment error for customer cus_123.

Note that if the Stripe customer has additional cards that are saved, those cards are not used. Only the card used on the originally authorized charge is used.

Currency Mismatch

If the currency of the invoice is different from the currency of the Stripe charge an error message Stripe: currency mismatch is added to the memo of the invoice.

The currency of the invoice must match the currency of the payment. The integration cannot determine how much to capture if the currency does not match the invoice since that would require determining the exchange rate to use when capturing the payment.

In order to fix this issue, adjust the currency of the invoice connected to the charge.

Network or API errors

If there is a Stripe or NetSuite outage, or if there are network errors the capture operation is retried. Retries are run every hour for the next 72 hours until it succeeds. If it fails after 72 attempts, you must manually retry the operation in the SuiteSync dashboard.