> ## Documentation Index
> Fetch the complete documentation index at: https://docs.metronome.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrate with NetSuite

<Note>
  **Public Beta**

  Metronome's NetSuite integration is currently in a Public Beta. Breaking changes may occur between now and GA.

  Not all Metronome features are supported during Public Beta. Please contact your Metronome representative if you have questions.

  Features known to be unsupported:

  * Custom currencies
  * Account hierarchy
</Note>

Metronome's NetSuite integration enables clients to sync invoices and payments to NetSuite for two core use cases:

* **Billing:** Send invoices to NetSuite for distribution and collection.
* **Revenue recognition:** If a different system (e.g. Stripe) is used for billing, sync invoices and payment status to NetSuite to power revenue operations.

## NetSuite compatibility requirements

The NetSuite integration is available to all Metronome customers, but it is designed to work with standard NetSuite configurations. NetSuite is highly customizable, and your instance may require some baseline configuration updates before the integration works out of the box.

Before setting up the integration, confirm that your NetSuite instance meets the following requirements:

* **Line item fields:** The line item `amount`, `quantity`, and `total` fields must be writable.
* **Inventory items:** Inventory items that require a location are not supported.

<Info>
  **SANDBOX VALIDATION**

  Before enabling the integration in production, validate the full invoice sync flow in your NetSuite sandbox environment. This helps surface any configuration issues before they affect live invoices.
</Info>

<Info>
  **THROUGHPUT**

  This integraion supports up to 25,000 arrears invoices/month. If your invoice volume exceeds this amount, data may take longer than expected to sync to NetSuite.
</Info>

<Warning>
  **INSTANCE-SPECIFIC CUSTOMIZATIONS**

  Metronome does not modify the integration to accommodate custom NetSuite instance configurations. If your instance requires changes to be compatible, those updates will need to be made on your side.
</Warning>

## Connect Metronome to NetSuite

To connect Metronome to NetSuite, navigate to the Metronome UI and go to the *Connections -> Integrations* tab. Select NetSuite from the options in *Available Integrations*. A pop-up will open that will provide instructions on how to connect Metronome with NetSuite. You will need to:

* Provide Metronome with your NetSuite account ID
* Download a permissions bundle (provided in the pop-up screen) to your NetSuite account, which will ensure Metronome has the appropriate permissions to create and read from the necessary objects in NetSuite
* Provide Metronome with the generated credentials to access your NetSuite account

Once complete, you should see NetSuite listed under the *Active Integrations* table.

<Info>
  **INITIAL OBJECT SYNC**

  After creating the connection, it can take Metronome up to an hour to index objects inside of NetSuite. This may cause a delay in syncing invoices after initial set-up.
</Info>

## Map your Metronome products to NetSuite items

Metronome needs to map Metronome products to NetSuite items to ensure invoices sync successfully and revenue is allocated to the appropriate bucket:

* Create a custom field on the product object. Name it something like `netsuite_item_internal_id`.
* For each product in Metronome, set the field with the corresponding internal item ID in NetSuite.
* Use the edit mapping feature to set the relationship between the Metronome product custom field and the NetSuite item ID. Click on the NetSuite row in the **Active Integrations** table and select **Edit Mapping**.
* The mapping should look like `Invoice.Items: internal_id -> ContractProduct: your key`

## Configure your Metronome customer

Create either billing or revenue system configurations on the Metronome customer object. Once created, these can then be referenced on the customer's contract to route contract invoices to NetSuite:

* **Customer billing configuration:** For billing use cases, Metronome syncs the invoice to NetSuite once the invoice is finalized. NetSuite then handles invoice distribution, tax calculation, and payment collection.
* **Revenue system configuration:** Metronome syncs invoices to NetSuite after payment has been attempted in a different system (e.g. Stripe). If payment was successful, Metronome will sync the associated payment information to NetSuite as a payment object. If payment fails upon first attempt but later succeeds, Metronome will create the payment object once successful.

### Set the customer billing configuration

If a customer should be billed out of NetSuite, set the `customer_billing_configuration` as `netsuite`. This can either be done in the customer create call or after customer creation using the `/setCustomerBillingProviderConfigurations` end point or the UI. See example below:

```bash theme={null}
curl https://api.metronome.com/v1/setCustomerBillingProviderConfigurations \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "data": [
      {
        "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491",
        "billing_provider": "netsuite",
        "configuration": {
          "netsuite_customer_id": "58877111"
        },
        "delivery_method_id": "5b95d955-b705-41c8-9d2e-34ccbdee5193"
      }
    ]
  }'
```

<Info>
  **SET CONFIGURATION ON CONTRACT**

  Metronome allows you to set multiple `customer_billing_configuration` per customer. Given this, once a `customer_billing_configuration` has been set, you must set the config on the relevant contract in order for Metronome to send the contract invoices to NetSuite.
</Info>

### Set the revenue system configuration

If the customer is billed outside of NetSuite, but NetSuite needs the invoice information for revenue recognition, set up a `revenue_system_configuration` for the customer via the API or UI. Metronome syncs both invoices and payments (if available) for contracts with a revenue system configuration.

If payment fails for the invoice after the first attempt, Metronome will still sync the invoice to NetSuite as `OPEN`. If payment is reattempted later and succeeds, Metronome will retroactively update the associated invoice in NetSuite as 'PAID'.

See an example below for setting the `revenue_system_configuration` via the `setCustomerRevenueSystemConfigurations` end point:

```bash theme={null}
curl https://api.metronome.com/v1/setCustomerRevenueSystemConfigurations \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "data": [
		{
			"customer_id": "7b8864ad-5238-4ec2-8b89-bee635e1876b",
      		"provider": "netsuite",
 			"configuration": {
 				"netsuite_customer_id": "58771"
 			},
 			"delivery_method_id": "6fe89b5a-41d0-413b-bb44-5f90522db8a2"
 		}
	]
}'
```

<Info>
  **SET CONFIGURATION ON CONTRACT**

  Metronome allows you to set multiple `revenue_system_configuration` per customer. Given this, once a `revenue_system_configuration` has been set, you must set the config on the relevant contract in order for Metronome to send the contract invoices and associated payments to NetSuite.
</Info>

### Provision the customer's contract

Either the `customer_billing_configuration` or the `revenue_system_configuration` need to be set on a contract in order for Metronome to sync invoices to NetSuite. This provides you with flexibility to route invoices to different places on a per contract basis.

Let's look at an example of a company:

* All PLG customers are billed out of Stripe. These are self-serve customers that are charged a \$10 monthly subscription fee in return for 5 AI credits.
* All SLG customers are billed out of NetSuite. These customers pay in quarterly installments for annual usage commitments.

For PLG customers, I want Metronome to collect payment in Stripe and then sync the invoice to NetSuite. To enable this, there are two API calls I need to make to Metronome when a new PLG customer signs up: create a customer and create a contract.

See example below for creating the customer object. This API call includes the creation of the `customer_billing_configuration`, and `revenue_system_configuration`:

```bash theme={null}
curl https://api.metronome.com/v1/customers \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
		  "ingest_aliases": [
		    "plgcustomer1@example.com"
		  ],
		  "name": "Customer 01",
		  "customer_billing_provider_configurations": [
			{
				"billing_provider": "stripe",
				"delivery_method": "direct_to_billing_provider",,
				"configuration": {
					"stripe_customer_id": "cus_123",
        			"stripe_collection_method": "charge_automatically"
		    	}
			}
		  ],
		  "revenue_system_configuration": [
			{
	      		"provider": "netsuite",
	 			"configuration": {
	 				"netsuite_customer_id": "58771"
	 			},
	 			"delivery_method_id": "6fe89b5a-41d0-413b-bb44-5f90522db8a2"
			}
		  ]
	  }'
```

Next, see example below for creating the PLG contract for the customer with the `customer_billing_configuration` and `revenue_system_configuration` set on it. In order to get the `revenue_system_configuration_id` and `billing_provider_configuration_id`, you will need to call the fetch billing provider and revenue system configuration end-points:

```bash theme={null}
curl https://api.metronome.com/v1/customers \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
	  	"customer_id": "4c09936b-455d-4c72-a120-d71b600a7546",
		"rate_card_id": "740a2ca1-64f6-417d-807a-05f154b3b1fe",
		"starting_at": "2025-06-01T00:00:00.000Z",
		"billing_provider_configuration": {
		    "billing_provider_configuration_id": "e045c62b-65e7-4e84-a924-3f06f8b621d0" // UUID of previously created customer billing configuration
		},
		"revenue_system_configuration": {
			"revenue_system_configuration_id": "d455j33b-12f7-4b76-a924-3f06f8b687q9" // UUID of previously created revenue system configuration
		},
		"overrides": [
		    {
		        "starting_at": "2025-04-01T00:00:00.000Z",
		        "override_specifiers": [
		            {
		                "billing_frequency": "annual",
		                "product_id": "ed518bcb-acc1-4cd8-85dd-880c2eb38994"
		            }
	            ],
	            "entitled": true
		    }
		],
	    "subscriptions": [
	        {
	            "collection_schedule": "advance",
		        "initial_quantity": 1,
	            "proration": {
	                "invoice_behavior": "bill_on_next_collection_date",
		            "is_prorated": true
		        },
	            "subscription_rate": {
	                "billing_frequency": "monthly",
		            "product_id": "ed518bcb-acc1-4cd8-85dd-880c2eb38994"
		        },
	            "description": "Basic tier",
	            "name": "Basic Plan",
		        "custom_fields": {
			         "plan_tier": "basic"
		        },
	            "temporary_id": "basic_plan_monthly"
	        }
		],
	    "recurring_credits": [
	      {
		    "access_amount": {
		    	"credit_type_id": "d3cb2827-dcb5-44af-9354-947a7197b9a6",
		        "unit_price": 5
		    },
		    "commit_duration": {
	        	"value": 1,
		        "unit": "periods"
		    },
		    "priority": 1,
	        "product_id": "652e1298-7638-45a8-b691-cdf47e46cbc8",
	        "starting_at": "2025-06-01T00:00:00Z",
		    "subscription_config": {
		    	"subscription_id": "basic_plan_monthly",
		        "apply_seat_increase_config": {
		        	"is_prorated": true
		        }
		    }
		  }
		]
	  }'
```

For SLG customers, I want Metronome to sync the invoice to NetSuite where it can be billed. To enable this, the same API calls to create a PLG customer are required, but NetSuite should be created as a `customer_billing_configuration` on the customer and used as the billing config on the contract.

## Tax

To calculate tax for invoices in NetSuite, you need to integrate NetSuite with your preferred tax provider. Metronome does not calculate nor sync tax amounts to NetSuite. The tax flow will look as follows:

* Metronome creates an invoice in NetSuite.
* Tax integration in NetSuite adds tax to invoice.

This set-up is required regardless of whether you are using NetSuite for billing or just for revenue recognition.

Note that tax is **not** synced back to Metronome.

## Additional configuration

Metronome also syncs additional metadata to the NetSuite invoice object to help with reconciliation workflows. To enable, create the following custom fields on your NetSuite invoice object with the following `id` (all case sensitive):

* `metronome_invoice_id`: Metronome will store the associated Metronome `invoice_id` on this field.
* `metronome_contract_id`: Metronome will store the associated Metronome `contract_id` on this field.
* `metronome_customer_id`: Metronome will store the associated Metronome `customer_id` on this field.

If these custom fields are not set-up, Metronome will be unable to sync the associated metadata.

## Manage the integration

When Metronome sends invoices to NetSuite, it records information across four surface areas to help you manage state of each object and ensure all data is synced correctly: the UI, API, data export, and webhook notifications. Leverage this information to adjudicate potential sync issues and ensure all data successfully sends to NetSuite.

### Invoice state

Metronome will record information in distinct places on the invoice object depending on whether NetSuite is configured as the `customer_billing_configuration` or the `revenue_system_configuration`.

#### Successful syncs

When NetSuite is set as the `customer_billing_configuration`, sync details will be stored in the `external_invoice` object. The invoice status will be reflected in the `external_status` property and the created NetSuite invoice id is stored oin the `external_invoice.invoice_id` property. See a /getInvoice example below:

```bash theme={null}
curl https://api.metronome.com/v1/customers \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
	    "id": "8f653259-640d-5a10-9636-2c7682a355fe",
	    "start_timestamp": "2026-02-11T00:00:00+00:00",
        "end_timestamp": "2026-02-11T00:00:00+00:00",
	    "issued_at": "2026-02-11T00:00:00+00:00",
	    "customer_id": "43536714-7f62-4e27-abcd-492d231ab7a0",
		// ...
		"external_invoice": {
			"billing_provider_type": "netsuite",
	        "invoice_id": "61112", // NetSuite invoice id
	        "issued_at_timestamp": "2026-02-11T00:00:00+00:00",
	        "external_status": "FINALIZED"
			// ...
	}'
```

Upon initial success, Metronome will emit a `invoice.invoice_sync_status` webhook notification providing the invoice details:

```json theme={null}
{
  "id": "65472d2c-c51f-46b2-95b3-0eaeb5c3dc5a",
  "invoice_id": "a43c2489-3d2f-40a2-a469-16411c535406",
  "customer_id": "faeff926-0a94-45da-9048-5b9d381b608b",
  "contract_id": "dfaa1fd8-d4d7-42c0-b2ab-9cc532793ca7",
  "sync_type": "billing_provider,
  "external_invoice": {
  	"billing_provider_type": "netsuite",
	"invoice_id": "9ae574fb-9d56-51c2-9077-b78971e9fe5b", // NetSuite invoice id
	"issued_at_timestamp": "2026-02-11T00:00:00+00:00",
	"external_status": "FINALIZED",
	// ...
  }
}
```

If the invoice status changes in NetSuite, Metronome will update the `external_status` to reflect the new invoice state. Expect approximtely one-hour latency for these status updates.

When NetSuite is set as the `revenue_system_configuration`, sync details will be stored in the `revenue_system_invoices` object on the invoice API. See example below:

```bash theme={null}
curl https://api.metronome.com/v1/customers \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
	    "id": "8f653259-640d-5a10-9636-2c7682a355fe",
	    "start_timestamp": "2026-02-11T00:00:00+00:00",
        "end_timestamp": "2026-02-11T00:00:00+00:00",
	    "issued_at": "2026-02-11T00:00:00+00:00",
	    "customer_id": "43536714-7f62-4e27-abcd-492d231ab7a0",
		// ...
    	"revenue_system_invoices": [
        	{
	            "revenue_system_provider": "NETSUITE",
	            "revenue_system_external_entity_id": "458886",
	            "sync_status": "SUCCEEDED",
	            "revenue_system_external_entity_type": "NETSUITE_INVOICE"
            }
        ]
	}'
```

Similarly, Metronome will emit a `invoice.invoice_sync_status` webhook notification with `sync_type` set to `revenue_system`.

#### Sync failures

When NetSuite is set as the `customer_billing_configuration`, `external_status` will be updated to `INVALID_REQUEST_ERROR` in the event of a failure. The error message will be stored in the `billing_provider_error` property. See a /getInvoice API example below:

```bash theme={null}
curl https://api.metronome.com/v1/customers \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
	    "id": "8f653259-640d-5a10-9636-2c7682a355fe",
	    "start_timestamp": "2026-02-11T00:00:00+00:00",
        "end_timestamp": "2026-02-11T00:00:00+00:00",
	    "issued_at": "2026-02-11T00:00:00+00:00",
	    "customer_id": "43536714-7f62-4e27-abcd-492d231ab7a0",
		// ...
		"external_invoice": {
	        "billing_provider_type": "netsuite",
            "external_status": "INVALID_REQUEST_ERROR",
			"billing_provider_error": "We've encountered the following error when trying to access the NetSuite API: Failed to create Netsuite Invoice object. No item id found 5551."
		},
		// ...
	}'
```

When the error occurs, Metronome will emit a `invoice.invoice_sync_status` webhook notification providing the invoice details with associated error information. Clients should consume these webhooks to identify when an invoice fails to sync to NetSuite and adjudicate based on error details.

In the example given above, the error message identifies that the item id for one of the Metronome products is incorrect. To address this problem, update the corresponding custom field with the correct NetSuite item id. Once fixed, you can reattempt the sync to NetSuite via the UI by clicking **Send to NetSuite** button on the invoice UI page.

When NetSuite is set as the `revenue_system_configuration`, `sync_status` will be updated to `FAILED` in the event of a failure. The associated error for why the invoice failed will be stored in the `error_message` property. See example below:

```bash theme={null}
curl https://api.metronome.com/v1/customers \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
	    "id": "8f653259-640d-5a10-9636-2c7682a355fe",
	    "start_timestamp": "2026-02-11T00:00:00+00:00",
        "end_timestamp": "2026-02-11T00:00:00+00:00",
	    "issued_at": "2026-02-11T00:00:00+00:00",
	    "customer_id": "43536714-7f62-4e27-abcd-492d231ab7a0",
		// ...
        "revenue_system_invoices": [
            {
	            "revenue_system_provider": "NETSUITE",
	            "sync_status": "FAILED",
                "revenue_system_external_entity_type": "NETSUITE_INVOICE",
	            "error_message": "We've encountered the following error when trying to access the NetSuite API: Failed to create Netsuite Invoice object. No item id found 5551."
            }
        ]
	}'
```

### Payment state

If Stripe is used for billing and NetSuite is configured as the revenue system, Metronome will first create an invoice object in Stripe. If the payment is successful:

* Metronome will store the payment intent id and payment amount inside the `external_invoice` object in the `external_payment_id` and `invoiced_total` fields respectively.
* When then syncing the invoice to NetSuite, Metronome will mark the invoice as `PAID` and create a linked payment object.

Similar to the invoice sync, Metronome will emit a `payment.payment_status_sync` webhook notification to indicate success or failure of sending the payment object to NetSuite.

If NetSuite is used for billing, Metronome will create an invoice in NetSuite. When that invoice is paid in NetSuite, Metronome will mark the invoice as `PAID` once data is synced back from NetSuite.
