How to Perform Writeback from Palantir Foundry to NetSuite
In this guide, we’ll walk through the steps to perform a writeback from Palantir Foundry to NetSuite using REST APIs. Specifically, we’ll focus on batch writebacks with external transforms. This process can also be adapted for external Python functions or UDFs for use in the Pipeline Builder.
What is Writeback?
Writeback refers to updating or inserting data back into a source system. In our case, we’ll use NetSuite REST APIs to perform batch writebacks via external transforms. For more details, you can refer to the following documentation:
For user-initiated writebacks from frontend apps, consider setting up an outbound app using OAuth2 with NetSuite. This ensures user permissions are respected. This isn’t a part of this tutorial (but maybe I’ll write one in the future if there is interest). For more details, refer to:
Setting Up a Connection to NetSuite
- Choose Between SuiteQL or SuiteTalk:
- Enable Code Imports:
- Navigate to the Code Import configuration and enable code imports.
- Enable Export Configuration:
- If you plan to read datasets in your transformation, ensure exports to this source are enabled.
Example Dataset and External Transform
In this guide I’ll assume we have a dataset with the schema: "account_id", "new_name"
. This dataset contains account IDs for accounts we want to rename.
-
Set Up a New External Transform:
- Create a new Code Repository. For this example, we’ll use a lightweight transform due to the small data size.
-
Import Required Libraries:
- Use the sidebar to import the following libraries:
requests
,requests-oauthlib
,urllib3
,transforms-external-systems
.
- Use the sidebar to import the following libraries:
-
Add Your NetSuite Source:
- Include your NetSuite source in the External Systems sidebar.
Example Code for Writeback
Here’s a basic example of the code you’ll use. Make sure to replace placeholders with your NetSuite account details and dataset RIDs.
import polars as pl
import requests
from requests_oauthlib import OAuth1
from urllib.parse import urljoin
from transforms.api import transform, lightweight, Output, Input
from transforms.external.systems import external_systems, Source
# Constants
REALM = "YOUR_REALM_ID"
BASE_URL = "https://YOUR_REALM_ID.suitetalk.api.netsuite.com"
@lightweight(cpu_cores=1, memory_gb=1)
@external_systems(
netsuite_suiteql_source=Source(
"ri.magritte..source.99d712ea-d5b9-44ee-8850-7a9bbb847304"
)
)
@transform(
accounts_to_rename=Input(
"ri.foundry.main.dataset.418ea70d-1696-41ba-8f91-2adb8377c462"
),
writeback_results=Output(
"ri.foundry.main.dataset.b823e895-0a8f-426d-b665-42c25850a2f2"
),
)
def compute(netsuite_suiteql_source, accounts_to_rename, writeback_results):
"""
Main function to update account names in NetSuite and write results to a table.
"""
auth = get_oauth1_auth(netsuite_suiteql_source)
results = []
for account in accounts_to_rename.polars().iter_rows(named=True):
account_id = account["account_id"]
new_name = account["new_name"]
result = update_account_name(account_id, new_name, auth)
results.append(result)
result_df = pl.DataFrame(results)
writeback_results.write_table(result_df)
def get_oauth1_auth(netsuite_suiteql_source):
"""
Retrieve OAuth1 authentication credentials.
"""
return OAuth1(
client_key=netsuite_suiteql_source.get_secret("NETSUITE_TOKEN_AUTH_CLIENT_ID"),
client_secret=netsuite_suiteql_source.get_secret(
"NETSUITE_TOKEN_AUTH_CLIENT_SECRET"
),
resource_owner_key=netsuite_suiteql_source.get_secret(
"NETSUITE_TOKEN_AUTH_ACCESS_TOKEN"
),
resource_owner_secret=netsuite_suiteql_source.get_secret(
"NETSUITE_TOKEN_AUTH_ACCESS_TOKEN_SECRET"
),
signature_method="HMAC-SHA256",
realm=REALM,
)
def update_account_name(account_id, new_name, auth):
"""
Update the name of an account in NetSuite and return the result.
Parameters:
- account_id: The ID of the account to update.
- new_name: The new name to set for the account.
- auth: The OAuth1 authentication object.
Returns:
A dictionary containing the account ID, new name, status code, and response message.
"""
# We're following Netsuite API docs: https://system.netsuite.com/help/helpcenter/en_US/APIs/REST_API_Browser/record/v1/2024.2/index.html
# New API docs may appear here: https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_157373386674.html
url = urljoin(BASE_URL, f"/services/rest/record/v1/account/{account_id}")
payload = f'{{"acctName": "{new_name}"}}'
headers = {"Content-Type": "application/json"}
try:
response = requests.patch(url, data=payload, headers=headers, auth=auth)
return {
"account_id": account_id,
"new_name": new_name,
"status_code": response.status_code,
"response_message": response.text,
}
except requests.RequestException as e:
return {
"account_id": account_id,
"new_name": new_name,
"status_code": None,
"response_message": str(e),
}
This code sets up a lightweight transformation to update account names in NetSuite and writes the results to a table. Adjust the code as necessary for your specific use case.