Briar Rose is a Laravel-friendly NetSuite client that supports:
- SuiteTalk REST Web Services (REST Record) via OAuth 1.0a (HMAC-SHA256)
- RESTlets via OAuth 1.0a (HMAC-SHA256)
- Developer ergonomics: relative paths, pagination helpers, hydration helpers, retries/backoff.
- PHP ^8.2
- Laravel 10 / 11 / 12 (via illuminate components)
- NetSuite OAuth 1.0a integration (Consumer Key/Secret + Token ID/Secret)
composer require searsandrew/briar-roseBriar Rose supports configuration via environment variables (no config publish required).
NETSUITE_ACCOUNT=0000000
NETSUITE_BASE_URL=https://0000000.suitetalk.api.netsuite.com
NETSUITE_CONSUMER_KEY=...
NETSUITE_CONSUMER_SECRET=...
NETSUITE_TOKEN_ID=...
NETSUITE_TOKEN_SECRET=...NETSUITE_REST_DEFAULT_LIMIT=1000
NETSUITE_REST_RETRY=true
NETSUITE_REST_RETRY_MAX=5
NETSUITE_REST_RETRY_BASE_DELAY_MS=250
NETSUITE_REST_RETRY_MAX_DELAY_MS=5000NETSUITE_RESTLET_BASE_URL=https://0000000.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=0000&deploy=1
NETSUITE_RESTLET_SCRIPT_ID=...
NETSUITE_RESTLET_DEPLOY_ID=1Sandbox note: NetSuite sandbox account ids often use underscores in the OAuth realm. Briar Rose will normalize realm formatting for you.
You can call Briar Rose via the facade:
use Searsandrew\BriarRose\Facades\BriarRose;$response = BriarRose::rest()
->record('inventoryItem')
->get(0000);
$data = $response->json();$response = BriarRose::rest()
->record('inventoryItem')
->getFields(0000, ['id', 'itemId', 'displayName']);
$data = $response->json();$response = BriarRose::rest()
->record('classification')
->list(['limit' => 1000, 'offset' => 0]);
$page = $response->json(); // items + linksforeach (BriarRose::rest()->record('classification')->listAll(['limit' => 1000]) as $pageResponse) {
$page = $pageResponse->json();
}foreach (BriarRose::rest()->record('classification')->listItemsAll(['limit' => 1000]) as $item) {
// Usually contains id + links
$id = $item['id'] ?? null;
}foreach (BriarRose::rest()->record('classification')->listItemIdsAll(['limit' => 1000]) as $id) {
// $id is the internal id
}NetSuite supports a q query parameter for record collection filtering. Briar Rose exposes this directly:
$response = BriarRose::rest()
->record('inventoryItem')
->where('isinactive IS false', ['limit' => 1000]);
$page = $response->json();Note: NetSuite’s filtering syntax varies by record type. Refer to NetSuite docs for supported fields/operators.
Collection endpoints typically return id + links, not full records. If you want to cache “id + name” locally, hydrate each record.
$endpoint = BriarRose::rest()->record('classification');
foreach ($endpoint->hydrateAll(['limit' => 1000], ['id', 'name']) as $row) {
// $row includes the requested fields
}$endpoint = BriarRose::rest()->record('classification');
$endpoint->hydrateAll(
listQuery: ['limit' => 1000],
fields: ['id', 'name'],
onRow: function (array $row) {
// Your app code: upsert locally, cache, etc.
}
);You can call any RESTlet deployed to your account via the script method.
BriarRose::restlet()
->script(0000, 1)
->get(['listId' => 0000]);If you have a single RESTlet script deployed, you can set enviromental variables to call it directly:
Note: This is the preferred method for production use if you have a single RESTlet script deployed.
Set the deploy ID in the environment:
NETSUITE_RESTLET_SCRIPT_ID=... // Script ID of the deployed RESTlet
NETSUITE_RESTLET_DEPLOY_ID=1 // Booleans are 1 or 0$response = BriarRose::restlet('000')
->request('GET', ['listId' => 000]);If you have a RESTlet base URL set, you can call it like this:
Set the RESTlet base URL in the environment:
NETSUITE_RESTLET_BASE_URL=... // Be sure to set the Script ID of the RESTlet in the URL.$response = BriarRose::restlet()
->request('GET', ['listId' => 000]);
$data = $response->json();All requests return Illuminate\Http\Client\Response. Use standard helpers:
$response->successful();
$response->status();
$response->throw(); // throws RequestExceptionRetries/backoff are enabled by default for common transient failures (429 / 5xx) and honor Retry-After when present.
- SuiteQL endpoint helpers (paged queries, incremental sync patterns)
- Better query/filter helpers
- Additional first-class endpoints (as needed)
MIT