Stripe to NetSuite Invoice Import

Overview

This integration syncs Stripe invoices into NetSuite through PayPack, including the related Customer, Subscription and Payment details. For each Stripe invoice, PayPack can create or update the NetSuite Customer, Invoice, PayPack Subscription record, Credit Memo and Customer Payment.

All import modes (batch, on-demand, real-time) use the same PayPack configuration and field mappings, so results are consistent however an invoice arrives.

Import Modes

Mode Trigger Best for
Batch Scheduled script Ongoing, incremental sync
On-Demand Manual, by Stripe invoice ID Importing missing invoices
Real-Time Stripe webhook Immediate updates in NetSuite

Configuration Settings

All invoice settings can be found under the Invoices subtab in the Data Orchestration tab. The fields are grouped together under Stripe to NetSuite for easy access.

Note: Click any field label in the Invoices tab to see a description of its purpose and usage.

Field Descriptions

  • Enable Invoices Flow: Check/mark to enable importing Stripe invoices into NetSuite. Uncheck to stop all invoice imports.Invoice -enable.png
  • Enable Webhook for Invoices: Check/mark to let Stripe webhooks automatically sync invoices to NetSuite when they are finalized or paid.Invoice - webhook enable.png

  • Update Stripe Metadata: Check/mark to automatically write the NetSuite Invoice Internal ID back to the corresponding Stripe invoice after it is createdInvoice - update metadata.png

  • Last Exported Date: Shows the last time invoices were imported from Stripe, in Unix and date/time formats. The next import uses this value to fetch only invoices created after it (the created[gte] parameter). 

Note: This field is updated by the system after every flow execution and is read-only.Invoice - last exported.png

  • Date Offset:  Offset in milliseconds applied to the last successful export time. A negative value moves the export time backward and a positive value moves it forward. For example, -60000 is 1 minute earlier and 60000 is 1 minute later.

  • Status:  Select one or more invoice statuses to filter which Stripe invoices are imported.
  • Exclude $0 Invoices: Check/mark to automatically skip importing invoices with a total amount of zero.Invoice - exclude 0.png

  • Invoice Line Item: Maps each Stripe invoice line to the selected NetSuite item. Each line is imported with its own amount. 

Note: Taxes and discounts from Stripe will not be imported.invoice line item.jpg
 

  • Discount Item: Maps the NetSuite item that represents any discounts from Stripe invoices.

Note: Use only non-inventory items. All Stripe discounts appear as a single line on the NetSuite invoice.invoice discount item.jpg

  • Tax Item: Maps the NetSuite item that captures taxes from Stripe invoices.

Note: Use only non-inventory items. All Stripe taxes are combined into a single line on the NetSuite invoice.invoice tax item.jpg
 

  • Invoice Field Mappings: Controls how Stripe Invoice fields are mapped to NetSuite Invoice fields and allows you to include related customer data from the associated Stripe customer.
    Note: Fields from the Stripe invoice object can be used. Associated customer data is available via stripeCustomerData (e.g., stripeCustomerData.id, stripeCustomerData.email).invoice field mappings.jpg

 Item Mapping Hierarchy

  1. Configured items (Invoice Line, Discount, Tax, Unused Time, Applied Balance): each Stripe line is imported using the selected item with its own amount.
  2. Multiple line items: Invoice Field Mappings can link each Stripe line to a different NetSuite item.
    1. Leave the default Invoice Line Item field blank.
    2. Use static or dynamic lookups to choose the item for each line.
    3. Sublist mappings are required even when default items are set. They let you map beyond Item, Quantity and Amount.
  3. Unused time lines (for example, from subscription downgrades): map them with the unusedTime sublist. Each line becomes its own invoice line, even when several subscriptions are downgraded at once.
  4. Applied balance: map it with the appliedBalance sublist to add a separate line for the balance amount.

Note: 
1. Always map Item, Quantity, and Amount for tax and discount lines, plus other required fields. Quantity defaults to 1, and Amount comes from Stripe (total discounts or taxes).

2. Use the record mapping fields to map all required line-level fields.
3. Using the Invoice Line Item always adds a single line for the total amount from the Stripe Invoice.
4. For conditional mapping, always leave the default item fields blank and use static or dynamic mapping. Any values entered in these fields will override the conditional logic in the Invoice Field Mappings.

Refer to the Field Mapping Documentation for examples and detailed instructions on implementing conditional mappings.

Customer Payment Settings

  • Payment Account: Select the NetSuite account where Stripe payments will be recorded. All imported payments are posted to this account.invoice Payment account.jpg
     

  • Payment Method: Select the payment method in NetSuite for recording Stripe payments.

Note: To use condition-based mapping, leave the Payment Account and  Payment Method fields empty and use static or dynamic mapping. Filling in these fields sets a global default that overrides any conditional logic in the Customer Payment Field Mappings.

Refer to the Field Mapping Documentation for examples and detailed instructions on implementing conditional mappingsinvoice payment method.jpg

  • Customer Payment Field Mappings: Controls how Stripe Payment (Payment Intent) fields are mapped to NetSuite Customer Payment fields and allows inclusion of related invoice and customer data from the associated Stripe objects.

Note: Fields from the Stripe payment intent object can be used. Payment data is organized as an array within each payment object, with associated invoice and customer details available via parent objects (for example, parent.stripeInvoiceData.id, parent.stripeCustomerData.id).invoice customer payment field mappings.jpg

Customer Settings

  • Customer Field Mappings: Controls how Stripe Customer fields are mapped to NetSuite Customer fields

Note: Only fields from the Stripe customer object can be used.invoice customer field mappings.jpg

  • Criteria to find existing customer record: Defines how NetSuite finds an existing customer before creating a new one. Set one or more filters (for example, email or Stripe customer ID) combined with AND/OR logic. If a match is found, that customer is used. Otherwise a default customer is used if configured, or a new customer is created from the Customer Field Mappings.
    • If no criteria are set, matching defaults to email and/or Stripe customer ID.
    • When a default customer is used, the existing customer record and its Stripe Customer ID field are not update
       

For detailed JSON mapping examples and instructions, refer to the Field Mapping Documentation.
 

Advanced Settings

  • Import Unused Line Items: Controls how Stripe unused time lines (created during subscription upgrades or downgrades) are handled. When enabled, they are added to the NetSuite invoice. When disabled, they are left off the invoice and used to create Credit Memos instead.
  • Invoice Line Item for Unused Time: The NetSuite item used for unused time lines when they are added to the invoice. Applies only when Import Unused Line Items is enabled. Use only non-inventory items.
  • Applied Balance Handling: Defines how applied customer balances from Stripe are handled: as a line on the NetSuite invoice, or separately as a Credit Memo.
  • Invoice Line Item for Applied Balance: The NetSuite item used for the applied balance line. Use only non-inventory items.
  • Credit Memo Line Item: The NetSuite item used when creating Credit Memos from Stripe credit adjustments. Use only non-inventory items.
  • Credit Memo Field Mappings: Controls how Stripe credit-related invoice data maps to NetSuite Credit Memo fields. Related invoice and customer data is available through parent references such as parent.stripeInvoiceData.id. See the sample below.

High-Level Flow

Every import mode follows the same steps:

  1. Get invoices. Fetched from Stripe (Batch, On-Demand) or taken from the webhook payload (Real-Time). Invoices already in NetSuite, or that originated in NetSuite (identified by nsInvoiceId in Stripe metadata), are skipped. $0 invoices are skipped if Exclude $0 Invoices is on.
  2. Get all line items. Every line is retrieved, however many the invoice has. Unused time lines are handled according to Import Unused Line Items.
  3. Get the customer from Stripe.
  4. Get the subscription, if the invoice is linked to one.
  5. Get payment intents. Only paid payment intents for fully or partially paid invoices, up to 10 per run.
  6. Find or create the NetSuite customer using the matching criteria. If the customer exists under a different subsidiary, the subsidiary is added.
  7. Create or update the PayPack Subscription record, which can be linked to the invoice through the mapping.
  8. Create the invoice with lines, discounts and taxes per your mappings. An invoice needs at least one line. Applied balance is added as a line or deferred to a Credit Memo per your setting.
  9. Create Credit Memos when applied balance is set to Credit Memo, or when unused time lines are excluded from the invoice.
  10. Create Customer Payments for each successful payment intent and apply them to the invoice. Payments already imported (matched on Stripe Payment Intent ID) are not duplicated.

Script Details

Batch (Map/Reduce)

Script: PayPack_S2NS_Invoice_Import_MR_Batch. Runs on a schedule you define.

  • First run: fetches invoices created on or after the Invoice Start Date. Later runs fetch only invoices created after the Last Exported Date, so nothing is imported twice.
  • Parameters:
    • Stripe Account Id (custscript_pp_stripe_account_id): internal ID of the PayPack Stripe Account Configuration record.
    • Invoice Start Date (custscript_pp_inv_start_date): used only on the first run. Enter a Unix timestamp in seconds, for example 1761147332.

On-Demand (Map/Reduce)

Script: PayPack_S2NS_Invoice_Import_MR_OnDemand. Runs only when you trigger it. Use it mainly to import missing invoices.

  • Parameters:
    • Stripe Account Id (custscript_pp_od_stripe_account_id): internal ID of the PayPack Stripe Account Configuration record.
    • Stripe Invoice IDs (custscript_pp_od_stripe_invoice_ids): comma-separated, up to 10 IDs at a time.

Real-Time (Webhook)

Runs automatically when Stripe sends:

  • invoice.finalized: creates the open invoice in NetSuite.
  • invoice.paid: creates and applies the customer payment.

No parameters are needed. See Webhook Configuration to set up the webhook.

Deploying and scheduling

  1. Go to Customization > Scripting > Scripts.
  2. Filter by Type: Map/Reduce and open the Batch or On-Demand script.
  3. Click Deploy Script.
  4. Set the Stripe Account Id parameter to the internal ID of the relevant PayPack Stripe Account Configuration record.
  5. Batch: on the Schedule subtab, choose the event type (single, daily, weekly, monthly or yearly), start and end dates (or No End Date), and the repeat interval. Click Save.
  6. On-Demand: enter the invoice IDs and use Save and Execute.

Sample Invoice mapping (simple)

{
  "fields": [
    {
      "generate": "custbody_pp_stripe_invoice_id",
      "extract": "id"
    },
    {
      "generate": "duedate",
      "fieldType": "date",
      "extract": "due_date"
    },
    {
      "generate": "custbody25",
      "extract": "payments.data.0.payment.payment_intent"
    },
    {
      "generate": "custbody_pp_stripe_subscription_record",
      "extract": "nsSubscriptionId"
    }

  ],
  "sublist": {
    "item": [
      {
        "generate": "item",
        "dynamicLookup": {
          "recordType": "inventoryitem",
          "filters": [
            ["stockdescription","is",
              "{{lines.data[].pricing.price_details.product}}"
            ],"and",
            ["isinactive","is","F"]
          ],
          "resultField": "internalid",
          "default": "502"
        }
      },
      {
        "generate": "quantity",
        "handlebars": "{{lines.data[].quantity}}"
      },
      {
        "generate": "rate",
        "handlebars": "{{toFixed (divide lines.data[].pricing.unit_amount_decimal 100) 2}}"
      },
      {
        "generate": "location",
        "hardCodedValue": "2"
      },
      {
        "generate": "taxcode",
        "hardCodedValue": "-7"
      }
    ],
    "discount": [
      {
        "generate": "item",
        "extract": "total_discount_amounts[].discount",
        "staticLookup": {
          "map": {
            "di_1SKeCTCzzXCPoFbPIgJxwkgy": "1010",
            "di_1SFu9jCzzXCPoFbPApwQpRG6": "1010"
          },
          "default": 999
        }
      },
      {
        "generate": "quantity",
        "hardCodedValue": 1
      },
      {
        "generate": "amount",
        "handlebars": "-{{toFixed (divide total_discount_amounts[].amount 100) 2}}"
      },
      {
        "generate": "taxcode",
        "hardCodedValue": "-7"
      }
    ],
    "tax": [
      {
        "generate": "item",
        "hardCodedValue": "2"
      },
      {
        "generate": "location",
        "hardCodedValue": "2"
      },
      {
        "generate": "taxcode",
        "hardCodedValue": "-7"
      }
    ]
  }
}

Sample Invoice mapping (with unused time)

{
  "fields": [
    {
      "generate": "custbody_pp_stripe_invoice_id",
      "extract": "id"
    },
    {
      "generate": "duedate",
      "fieldType": "date",
      "extract": "due_date"
    },
    {
      "generate": "custbody25",
      "extract": "payments.data.0.payment.payment_intent"
    },
    {
      "generate": "custbody_pp_stripe_subscription_record",
      "extract": "nsSubscriptionId"
    }
  ],
  "sublist": {
    "item": [
      {
        "generate": "item",
        "dynamicLookup": {
          "recordType": "inventoryitem",
          "filters": [
            [
              "stockdescription",
              "is",
              "{{lines.data[].pricing.price_details.product}}"
            ],
            "and",
            [
              "isinactive",
              "is",
              "F"
            ]
          ],
          "resultField": "internalid",
          "default": "502"
        }
      },
      {
        "generate": "quantity",
        "handlebars": "{{lines.data[].quantity}}"
      },
      {
        "generate": "rate",
        "handlebars": "{{toFixed (divide lines.data[].pricing.unit_amount_decimal 100) 2}}"
      },
      {
        "generate": "location",
        "hardCodedValue": "2"
      },
      {
        "generate": "taxcode",
        "hardCodedValue": "-7"
      }
    ],
    "unusedTime": [
      {
        "generate": "item",
        "hardCodedValue": "714"
      },
      {
        "generate": "quantity",
        "extract": "lines.data[].quantity"
      },
      {
        "generate": "price",
        "hardCodedValue": "-1"
      },
      {
        "generate": "amount",
        "handlebars": "{{toFixed (divide lines.data[].amount 100) 2}}"
      },
      {
        "generate": "location",
        "hardCodedValue": "1"
      },
      {
        "generate": "taxcode",
        "hardCodedValue": "-7"
      }
    ],
    "discount": [
      {
        "generate": "item",
        "extract": "total_discount_amounts[].discount",
        "staticLookup": {
          "map": {
            "di_1SKeCTCzzXCPoFbPIgJxwkgy": "1010",
            "di_1SFu9jCzzXCPoFbPApwQpRG6": "1010"
          },
          "default": 999
        }
      },
      {
        "generate": "quantity",
        "hardCodedValue": 1
      },
      {
        "generate": "rate",
        "handlebars": "-{{toFixed (divide total_discount_amounts[].amount 100) 2}}"
      },
      {
        "generate": "taxcode",
        "hardCodedValue": "-7"
      }
    ],
    "tax": [
      {
        "generate": "item",
        "hardCodedValue": "2"
      },
      {
        "generate": "location",
        "hardCodedValue": "2"
      },
      {
        "generate": "taxcode",
        "hardCodedValue": "-7"
      }
    ],
    "appliedBalance": [
      {
        "generate": "item",
        "hardCodedValue": "502"
      },
      {
        "generate": "quantity",
        "hardCodedValue": 1
      },
      {
        "generate": "price",
        "hardCodedValue": "-1"
      },
      {
        "generate": "amount",
        "handlebars": "{{toFixed (divide creditBalance 100) 2}}"
      },
      {
        "generate": "location",
        "hardCodedValue": "1"
      },
      {
        "generate": "taxcode",
        "hardCodedValue": "-7"
      }
    ]
  }
}


 

 

Sample Customer Payment Field mappings

{
 "fields": [
   {
     "generate": "payment",
     "handlebars": "{{toFixed (divide amount 100) 2}}"
   },
   {
     "generate": "custbody_pp_s2ns_payment_intent_id",
     "extract": "id",
     "fieldType": "internalid"
   },
   {
     "generate": "custbody_nm_stripe_dcharge_id",
     "extract": "latest_charge.id"
   }
 ],
 "sublist": {
   "apply": [
     {
       "generate": "apply",
       "hardCodedValue": "T"
     },
     {
       "generate": "doc",
       "extract": "payment_details.order_reference"
     }
   ]
 }
}

Sample Customer Field mappings

{
 "fields": [
   {
     "generate": "subsidiary",
     "hardCodedValue": "1"
   },
   {
     "generate": "companyname",
     "extract": "stripeCustomerData.name"
   },
   {
     "generate": "custentity_nm_stripecharge_customer_id",
     "extract": "stripeCustomerData.id"
   }
 ]
}

Note: stripeCustomerData refers to the JSON object that contains the customer data from Stripe. In the sample above, the name and id are extracted from this object.

Sample Criteria to find existing customer record

{
 "filters": [
   [
     "custentity_nm_stripecharge_customer_id",
     "is",
     "{{customer}}"
   ]
 ],
 "default": ""
}

Note: The above sample criteria allows the flow to create a NetSuite Customer record is there is no existing customer record in NetSuite with the Stripe ID. If default has a value like "default": "123", no customer record will be created and a default customer with NetSuite Internal ID 123 will be used for the Invoice, Payment and Credit Memo (if applicable) 

Sample Credit Memo Field

{
  "fields": [
    { "generate": "location", "hardCodedValue": "<LOCATION_ID>" },
    { "generate": "custbody_pp_s2ns_credit_memo_id", "extract": "ns_cm_id" },
    { "generate": "custbody_stripe_invoice_id", "extract": "parent.stripeInvoiceData.id" }
  ],
  "sublist": {
    "item": [
      { "generate": "item", "hardCodedValue": "<CREDIT_MEMO_ITEM_ID>" },
      { "generate": "location", "hardCodedValue": "<LOCATION_ID>" },
      { "generate": "quantity", "hardCodedValue": "1" },
      { "generate": "price", "hardCodedValue": "-1" },
      { "generate": "amount", "handlebars": "{{toFixed credit_amount 2}}" },
      { "generate": "taxcode", "hardCodedValue": "<TAX_CODE_ID>" }
    ],
    "apply": [
      { "generate": "doc", "extract": "parent.stripeInvoiceData.nsInvoiceId" },
      { "generate": "apply", "hardCodedValue": true },
      { "generate": "amount", "extract": "credit_amount" }
    ]
  }
}
Was this article helpful?
0 out of 0 found this helpful

More resources