When I query NS API using this URL:
https://'.$accountID.'.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql
It returns to me whatever I specify in my body (e.g. SELECT * FROM customer
)
However, when I try to query it using this URL(it has a limit param):
https://'.$accountID.'.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=6
It does not work and returns the error showed down below
{
"type":"https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2",
"title":"Unauthorized",
"status":401,
"o:errorDetails":[
{
"detail":"Invalid login attempt. For more details, see the Login Audit Trail in the NetSuite UI at Setup > Users/Roles > User Management > View Login Audit Trail.",
"o:errorCode":"INVALID_LOGIN"
}
]
}
I suppose the problem could be either in the way I pass parameters (e.g. limit
) or in the generation of the signature.
If I run this query in PostMan it works, but when it comes to PHP it does not work with any parameters I pass to Netsuite API.
If I open "Login Audit Trail Search", you can see that URL column has no ?limit=7
just like this: /services/rest/query/v1/suiteql
, and the "Detail" columns says InvalidSignature
The code I am using within PHP is:
$httpMethod ="POST";
$accountID = 'NNNNNNN-sb1';
$realm = "NNNNNNN_SB1";
// this one is working fine
$url = 'https://'.$accountID.'.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql';
// when adding this limit it throws the error in PHP code (but postman works fine)
$url = 'https://'.$accountID.'.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql?limit=6';
$ckey = "NNNNN"; //Consumer Key
$csecret = "NNNNN"; //Consumer Secret
$tkey = "NNNNN"; //Token ID
$tsecret = "NNNNN"; //Token Secret
$timestamp = time();
$nonce = md5(mt_rand());
$signatureMethod = 'HMAC-SHA256';
$data["q"] = "SELECT * FROM customer WHERE LENGTH(externalid) = 32";
$baseString = $httpMethod . '&' . rawurlencode($url) . '&'
. rawurlencode(
"oauth_consumer_key=" . rawurlencode($ckey)
. "&oauth_nonce=" . rawurlencode($nonce)
. "&oauth_signature_method=" . rawurlencode($signatureMethod)
. "&oauth_timestamp=" . rawurlencode($timestamp)
. "&oauth_token=" . rawurlencode($tkey)
. "&oauth_version=1.0"
);
$key = rawurlencode($csecret) . '&' . rawurlencode($tsecret);
$signature = base64_encode(hash_hmac('sha256', $baseString, $key, true));
$signature = rawurlencode($signature);
$header = array(
"Authorization: OAuth realm=\"$realm\", oauth_consumer_key=\"$ckey\", oauth_token=\"$tkey\", oauth_nonce=\"$nonce\", oauth_timestamp=\"$timestamp\", oauth_signature_method=\"$signatureMethod\", oauth_version=\"1.0\", oauth_signature=\"$signature\"",
'Cookie: NS_ROUTING_VERSION=LAGGING',
'prefer: transient',
'Content-Type: text/plain',
'Accept: */*',
'Content-length: ' . strlen(json_encode($data)),
);
$curl = curl_init();
$opts = array(
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => $httpMethod,
CURLOPT_HTTPHEADER => $header,
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => json_encode($data)
);
curl_setopt_array($curl, $opts);
$response = curl_exec($curl);
curl_close($curl);
Screenshots (netsuite settings and postman): https://i.sstatic.net/2KtuJ.jpg
NS - netsuite
A friend of mine helped me really much, and we have an answer to this ambiguous question. Here is the code solution.
<?php
$httpMethod ="POST";
$accountID = 'NNNNNNN-sb1';
$realm = "NNNNNNN_SB1";
// this one is working fine
$baseUrl = 'https://'.$accountID.'.suitetalk.api.netsuite.com/services/rest/query/v1/suiteql';
$ckey = "NNNNN"; //Consumer Key
$csecret = "NNNNN"; //Consumer Secret
$tkey = "NNNNN"; //Token ID
$tsecret = "NNNNN"; //Token Secret
$timestamp = time();
$nonce = md5(mt_rand());
$signatureMethod = 'HMAC-SHA256';
$data["q"] = "SELECT * FROM customer WHERE LENGTH(externalid) = 32";
$baseString = $httpMethod . '&' . rawurlencode($baseUrl) . '&'
. rawurlencode(
//APPLY PARAMETERS IN ALPHABETICAL ORDER, URL ENCODED IN HERE
"limit=2"
. "&oauth_consumer_key=" . rawurlencode($ckey)
. "&oauth_nonce=" . rawurlencode($nonce)
. "&oauth_signature_method=" . rawurlencode($signatureMethod)
. "&oauth_timestamp=" . rawurlencode($timestamp)
. "&oauth_token=" . rawurlencode($tkey)
. "&oauth_version=1.0"
. "&offset=2"
);
$key = rawurlencode($csecret) . '&' . rawurlencode($tsecret);
$signature = base64_encode(hash_hmac('sha256', $baseString, $key, true));
$signature = rawurlencode($signature);
$header = array(
"Authorization: OAuth realm=\"$realm\", oauth_consumer_key=\"$ckey\", oauth_token=\"$tkey\", oauth_nonce=\"$nonce\", oauth_timestamp=\"$timestamp\", oauth_signature_method=\"$signatureMethod\", oauth_version=\"1.0\", oauth_signature=\"$signature\"",
'Cookie: NS_ROUTING_VERSION=LAGGING',
'prefer: transient',
'Content-Type: text/plain',
'Content-length: ' . strlen(json_encode($data)),
);
$curl = curl_init();
$opts = array(
CURLOPT_URL => $baseUrl . '?limit=2&offset=2', // APPLY LIMIT MANUALLY HERE
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => $httpMethod,
CURLOPT_HTTPHEADER => $header,
CURLOPT_POSTFIELDS => json_encode($data)
);
curl_setopt_array($curl, $opts);
$response = curl_exec($curl);
curl_close($curl);
var_dump($response);
exit;