JSON Field Mapping GuideUpdated 2 days ago
Overview
Mappings define how PayPack transfers data between Stripe and NetSuite.
In the context of this guide and its examples, Stripe serves as the source system, and NetSuite is the destination. Each mapping pairs a source field from one system with a destination field in the other to ensure accurate data flow.
Example:
1{2 "generate": "duedate",3 "extract": "due_date"4}
What this means:
Take the due_date from Stripe and populate NetSuite’s duedate field.
Structure
The JSON is divided into two main parts:
Section | Purpose |
fields | Top-level or main record fields in NetSuite (e.g., due date, department) |
sublist | Line-level details such as items |
Here’s a simplified view:
1{2 "fields": [ ... ],3 "sublist": {4 "item": [ ... ]5 }6}
Mapping Options in PayPack
PayPack supports multiple mapping options that determine how data from Stripe is transferred to NetSuite. Some options apply to both body-level and line-level fields, while others are available only at the body level.
Body-level fields map directly to properties on the main record object. For example, you can use a Handlebars expression like {{due_date}} to populate the invoice date.
Line-level fields map to objects within a sublist array, such as item or apply. Expressions must account for the array structure—for example, {{lines.0.amount}} to map the first line’s amount from Stripe to the Item sublist in NetSuite.
Options Available
The following options apply to body-level and/or line-level fields, as they affect how the record is initialized and how specific data types are handled in NetSuite.
useTheValueForRecordInitialization – Ensures certain fields are set when the record is first created in NetSuite, rather than afterward. This option is only available at the body-level.
fieldType – Defines the data type (e.g., date, currency, text) to ensure NetSuite interprets the mapped value correctly. This option is available at the body-level and line-level.
hardCodedValue – Assigns a fixed value to a field. This option is available at the body-level and line-level.
extract – Retrieves a value from the Stripe payload using a specified path. This option is available at the body-level and line-level.
Handlebars – Performs dynamic calculations or data formatting directly within the mapping. This option is available at the body-level and line-level.
staticLookup – Maps incoming values using a predefined, static value map. This option is available at the body-level and line-level.
dynamicLookup – Performs a real-time search in NetSuite to find and return the correct record and Internal ID. This option is available at the body-level and line-level.
Option | Purpose | Body-Level Example | Line-Level Example |
useTheValueForRecordInitialization | Certain fields must be populated when a NetSuite record is first created, not after. The useTheValueForRecordInitialization property handles this. | { "generate": "entity", "hardCodedValue": 1, "useTheValueForRecordInitialization": true } | Not Applicable |
fieldType | Using the fieldType property ensures that NetSuite interprets the value correctly. | { "fields": [ { "generate": "duedate", "extract": "due_date", "fieldType": "date" } ] } | { "fields": [...], "sublist": { "item": [ { "generate": "custitem26", "extract": "lines.data[].period.end", "fieldType": "date" } ] } } |
hardCodedValue | Sets a fixed value | {"fields": [ { "generate": "custbody25", "hardCodedValue": "78946" } ]} | { "fields": [...], "sublist": { "item": [ { "generate": "location", "hardCodedValue": "2" } ] } } |
extract | Pulls a value from Stripe data | {"fields": [ { "generate": "custbody_pp_stripe_invoice_id", "extract": "id" } ]} | { "fields": [...], "sublist": { "item": [ { "generate": "quantity", "extract": "lines.data[].quantity" } ] } } |
Handlebars | Performs calculations or transformations | { "generate": "memo", "handlebars": "{{toFixed (divide amount 100) 2}}" } | { "fields": [...], "sublist": { "item": [ { "generate": "rate", "handlebars": "{{toFixed (divide lines.data[].pricing.unit_amount_decimal 100) 2}}" } ] } } |
staticLookup | Maps a value using a predefined map | {"fields": [ { "generate": "currency", "extract": "currency", "staticLookup": { "map": { "usd": 1, "eur": 2 }, "default": 3 } } ]} | { "fields": [...], "sublist": { "item": [ { "generate": "item", "extract": "lines.data[].pricing.price_details.product", "staticLookup": { "map": { "prod_THs2r4MlsMSkBw": "2014", "prod_Q1QFO7q1rsBuYu": "503" }, "default": 501 } ] } } |
dynamicLookup | Searches NetSuite in real time | { "fields": [ { "generate": "currency", "dynamicLookup": { "recordType": "currency", "filters": [ ["symbol","is","{{currency}}"] ], "resultField": "internalid", "default": 1 } } ] } | { "fields": [...], "sublist": { "item": [ { "generate": "item", "dynamicLookup": { "recordType": "inventoryitem", "filters": [ ["stockdescription","is", "{{lines.data[].pricing.price_details.product}}" ],"and", ["isinactive","is","F"] ], "resultField": "internalid", "default": "502" } } ] } } |
⚡ Tip: Even though the mapping options are identical, you must adjust paths and expressions according to the record.
Support Tax and Discount Lines Mapping
Mappings handle tax and discount line items as separate sublists (but considered as an item) within an invoice or transaction. Each sublist describes how to populate the relevant NetSuite fields using data from Stripe or fixed values.
This approach allows us to add necessary field mappings within the item sublist when discounts and taxes are represented as separate line items on NetSuite transaction records.
Taxes can be handled in two ways:
Inclusive — the tax is already part of the item price. For items priced with tax included in NetSuite, include the ignoreInclusiveTax mapping to ignore the inclusive tax and keep totals accurate. Refer to the example shown in the tax mappings below.
Exclusive — the tax is not added to the item price. When an item on the invoice is tax-exclusive (and the NetSuite rate field is mapped to Stripe item price before tax), the ignoreInclusiveTax mapping isn’t needed. Tax will appear as a separate line to match the total.
Note: When mapping tax and discount lines, always ensure that the fields item, quantity, and amount are included as mandatory fields, regardless of other required fields at the line level.
If you only need to map discounts, you can include just the discount array inside the sublist. Similarly, if only taxes need to be mapped, you can include only the tax array.
1{2 "fields": [...],3 "sublist": {4 "discount": [5 {6 "generate": "item",7 "extract": "total_discount_amounts[].discount",8 "staticLookup": {9 "map": {10 "di_1SKeCTCzzXCPoFbPIgJxwkgy": "1010",11 "di_1SFu9jCzzXCPoFbPApwQpRG6": "1010"12 },13 "default": 99914 }15 },16 {17 "generate": "quantity",18 "hardCodedValue": 119 },20 {21 "generate": "amount",22 "handlebars": "-{{toFixed (divide total_discount_amounts[].amount 100) 2}}"23 },24 {25 "generate": "taxcode",26 "hardCodedValue": "-7"27 }28 ],29 "tax": [30 {31 "generate": "item",32 "hardCodedValue": "2"33 },34 {35 "generate": "location",36 "hardCodedValue": "2"37 },38 {39 "generate": "taxcode",40 "hardCodedValue": "-7"41 },42 {43 "generate": "ignoreInclusiveTax",44 "hardCodedValue": "true"45 }46 ]47 }48}
Sample Invoice mapping commonly used
1{2 "fields": [3 {4 "generate": "custbody_pp_stripe_invoice_id",5 "extract": "id"6 },7 {8 "generate": "duedate",9 "fieldType": "date",10 "extract": "due_date"11 },12 {13 "generate": "custbody25",14 "extract": "payments.data.0.payment.payment_intent"15 }16 ],17 "sublist": {18 "item": [19 {20 "generate": "item",21 "dynamicLookup": {22 "recordType": "inventoryitem",23 "filters": [24 ["stockdescription","is",25 "{{lines.data[].pricing.price_details.product}}"26 ],"and",27 ["isinactive","is","F"]28 ],29 "resultField": "internalid",30 "default": "502"31 }32 },33 {34 "generate": "quantity",35 "handlebars": "{{lines.data[].quantity}}"36 },37 {38 "generate": "rate",39 "handlebars": "{{toFixed (divide lines.data[].pricing.unit_amount_decimal 100) 2}}"40 },41 {42 "generate": "location",43 "hardCodedValue": "2"44 },45 {46 "generate": "taxcode",47 "hardCodedValue": "-7"48 }49 ],50 "discount": [51 {52 "generate": "item",53 "extract": "total_discount_amounts[].discount",54 "staticLookup": {55 "map": {56 "di_1SKeCTCzzXCPoFbPIgJxwkgy": "1010",57 "di_1SFu9jCzzXCPoFbPApwQpRG6": "1010"58 },59 "default": 99960 }61 },62 {63 "generate": "quantity",64 "hardCodedValue": 165 },66 {67 "generate": "amount",68 "handlebars": "-{{toFixed (divide total_discount_amounts[].amount 100) 2}}"69 },70 {71 "generate": "taxcode",72 "hardCodedValue": "-7"73 }74 ],75 "tax": [76 {77 "generate": "item",78 "hardCodedValue": "2"79 },80 {81 "generate": "location",82 "hardCodedValue": "2"83 },84 {85 "generate": "taxcode",86 "hardCodedValue": "-7"87 }88 ]89 }90}
Sample customer payment mapping commonly used
1{2 "fields": [3 {4 "generate": "payment",5 "handlebars": "{{toFixed (divide amount 100) 2}}"6 },7 {8 "generate": "custbody_pp_s2ns_payment_intent_id",9 "extract": "id",10 "fieldType": "internalid"11 },12 {13 "generate": "custbody_nm_stripe_dcharge_id",14 "extract": "latest_charge"15 }16 ],17 "sublist": {18 "apply": [19 {20 "generate": "apply",21 "hardCodedValue": "T"22 },23 {24 "generate": "doc",25 "extract": "parent.stripeInvoiceData.nsInvoiceId"26 }27 ]28 }29}
Examples
Hardcoded Value
1{2 "sublist": {3 "apply": [4 {5 "generate": "apply",6 "hardCodedValue": "T"7 }8 ]9 }10}
Handlebars
1{2 "sublist": {3 "discount": [4 {5 "generate": "amount",6 "handlebars": "-{{toFixed (divide total_discount_amounts[].amount 100) 2}}"7 }8 ]9 }10}
Extract – Simple Path
1{2 "sublist": {3 "apply": [4 {5 "generate": "doc",6 "extract": "parent.stripeInvoiceData.nsInvoiceId"7 }8 ]9 }10}
Extract – Path with Array
1{2 "sublist": {3 "generate": "quantity",4 "handlebars": "{{lines.data[].quantity}}"5 }6}
Static Lookup – Simple Key
1{2 "sublist": {3 "item": [4 {5 "generate": "custcol_nm_vstyledesc",6 "extract": "id",7 "staticLookup": {8 "map": {9 "in_1SHhaFCzzXCPoFbP9hFIZ8HO": "in_1SHhaFCzzXCPoFbP9hFIZ8HO",10 "in_1SIPUEGuTaMUDQinGPQRX2TN": "in_1SIPUEGuTaMUDQinGPQRX2TN"11 },12 "default": "in_1SHhaFCzzXCPoFbP9hFIZ8HO"13 }14 }15 ]16 }17}
Static Lookup – Path Key
1{2 "sublist": {3 "item": [4 {5 "generate": "custcol_nm_vstyledesc",6 "extract": "customer_shipping.address.city",7 "staticLookup": {8 "map": {9 "Oakland": "Oakland",10 "New York": "New York"11 },12 "default": "Oakland"13 }14 },1516 ]17 }18}
Static Lookup – Path with Array
1{2 "sublist": {3 "generate": "item",4 "extract": "total_taxes[].tax_rate_details.tax_rate",5 "staticLookup": {6 "map": {7 "di_1SFu9rCzzXCPoFbPKdHgMuxj": "1010",8 "di_1SFu9jCzzXCPoFbPApwQpRG6": "1010"9 },10 "default": 101011 }12 }13}
Dynamic Lookup – Extract Direct
1{2 "sublist": {3 "apply": [4 {5 "generate": "line",6 "dynamicLookup": {7 "recordType": "invoice",8 "filters": [9 [10 "custbody25",11 "is",12 "{{id}}"13 ]14 ],15 "resultField": "internalid",16 "default": ""17 }18 }19 ]20 }21}
Dynamic Lookup – Extract with Path
1{2 "sublist": {3 "apply": [4 {5 "generate": "line",6 "dynamicLookup": {7 "recordType": "invoice",8 "filters": [9 [10 "internalid",11 "is",12 "{{parent.stripeInvoiceData.nsInvoiceId}}"13 ]14 ],15 "resultField": "internalid",16 "default": ""17 }18 }19 ]20 }21}
Dynamic Lookup – Extract with Path and Array
1{2 "sublist": {3 "item": [4 {5 "generate": "item",6 "dynamicLookup": {7 "recordType": "inventoryitem",8 "filters": [9 [10 "stockdescription",11 "is",12 "{{lines.data[].pricing.price_details.product}}"13 ],14 "and",15 [16 "isinactive",17 "is",18 "F"19 ]20 ],21 "resultField": "internalid",22 "default": "502"23 }24 }25 ]26 }27}
Dynamic Lookup – with OR in the filter, formula text
1{2 "sublist": {3 "apply": [4 {5 "generate": "line",6 "dynamicLookup": {7 "recordType": "invoice",8 "filters": [9 [10 [11 [12 "custbody_pp_stripe_invoice_id",13 "is",14 "{{parent.stripeInvoiceData.id}}"15 ],16 "OR",17 [18 "custbody25",19 "is",20 "{{parent.stripeInvoiceData.id}}"21 ]22 ],23 "AND",24 [25 "mainline",26 "is",27 "T"28 ]29 ]30 ],31 "resultField": "internalid",32 "default": ""33 }34 }35 ]36 }37}
Date Field
1{2 "sublist": {3 "apply": [4 {5 "generate": "duedate",6 "extract": "parent.stripeInvoiceData.due_date",7 "fieldType": "date"8 }9 ]10 }11}
Text Field
1{2 "sublist": {3 "apply": [4 {5 "generate": "refnum",6 "dynamicLookup": {7 "recordType": "invoice",8 "filters": [9 [10 "internalid",11 "is",12 "{{parent.stripeInvoiceData.nsInvoiceId}}"13 ],14 "and",15 [16 "mainline",17 "is",18 "T"19 ]20 ],21 "resultField": "tranid",22 "default": ""23 },24 "fieldType": "text"25 }26 }27 }28}
Adding a discount item as line level
1{2 "sublist": {3 "discount": [4 {5 "generate": "item",6 "extract": "total_discount_amounts[].discount",7 "staticLookup": {8 "map": {9 "di_1SKeCTCzzXCPoFbPIgJxwkgy": "1010",10 "di_1SFu9jCzzXCPoFbPApwQpRG6": "1010"11 },12 "default": 99913 }14 },15 {16 "generate": "quantity",17 "hardCodedValue": 118 },19 {20 "generate": "amount",21 "handlebars": "-{{toFixed (divide total_discount_amounts[].amount 100) 2}}"22 },23 {24 "generate": "taxcode",25 "hardCodedValue": "-7"26 }27 ],28 }29}
Adding a tax item as line level
1{2 "sublist": {3 "tax": [4 {5 "generate": "item",6 "hardCodedValue": "2"7 },8 {9 "generate": "location",10 "hardCodedValue": "2"11 },12 {13 "generate": "taxcode",14 "hardCodedValue": "-7"15 }16 ]17 }18}