SUQODocs
User GuideAPI ReferenceSDKs

Configure the client

API key setup, environment inference and transport options for the SUQO PHP SDK.

Suqo\SuqoClient is the whole entry point: construct it, then reach a resource through one of its readonly properties. It is final and exposes resources and nothing else — no request method, no header hook, no mutable state.

Getting a key

Generate an API key in the API Integration section of your seller dashboard. Sandbox keys start su_test_key_, live keys start su_key_.

The SDK reads $SUQO_API_KEY when you pass nothing:

use Suqo\SuqoClient;

$suqo = new SuqoClient();                       // from $SUQO_API_KEY
$suqo = new SuqoClient(apiKey: 'su_test_key_…'); // or explicitly

The variable is read through getenv(), then $_ENV, then $_SERVER. An empty or absent key raises SuqoConfigError.

There's no separate environment flag

The key's prefix decides which host the SDK talks to: su_test_key_https://test-be.suqo.ai, su_key_https://be.suqo.ai. Swapping environments means swapping the key, and nothing else.

You can pass environment — but it is a check, never an override:

$suqo = new SuqoClient(apiKey: $key, environment: 'sandbox');

If it disagrees with the prefix, construction raises SuqoConfigError rather than quietly sending a live key to the sandbox or the reverse.

The resolved configuration is readable:

echo $suqo->config->environment->value;   // "sandbox"
echo $suqo->config->baseUrl;              // "https://test-be.suqo.ai"

Constructor options

public function __construct(
    ?string $apiKey = null,
    Environment|string|null $environment = null,
    ?float $timeout = null,
    ?int $maxRetries = null,
    LogLevel|string|null $logLevel = null,
    ?HttpClientInterface $httpClient = null,
)
ParameterDefaultNotes
apiKey$SUQO_API_KEYMust start su_test_key_ or su_key_.
environmentinferredA check against the prefix, never an override.
timeout30.0Seconds, per attempt — connect and total. Must be greater than zero.
maxRetries2Retries after the first attempt, so 2 means three attempts. Must be zero or greater.
logLevel$SUQO_LOG, else warndebug, info, warn, error, off.
httpClientnew CurlHttpClient()See Inject an HTTP client.
$suqo = new SuqoClient(
    apiKey: 'su_test_key_…',
    timeout: 30.0,
    maxRetries: 2,
    logLevel: 'warn',
);

Errors raised before any request is made

Construction raises Suqo\Exception\SuqoConfigError — a missing or malformed key, an environment that disagrees with the prefix, an unparseable environment or logLevel, a timeout of zero or less, a negative maxRetries.

use Suqo\Exception\SuqoConfigError;

try {
    $suqo = new SuqoClient(apiKey: $key);
} catch (SuqoConfigError $e) {
    fwrite(STDERR, $e->getMessage() . PHP_EOL);
    exit(1);
}

SuqoConfigError extends SuqoError, so a single catch (SuqoError) covers startup and runtime alike.

One asymmetry worth knowing: an unrecognised $SUQO_LOG value falls back to the default rather than failing construction — the environment is not the caller's call site. An unrecognised logLevel argument does throw.

Validating a key without building a client

Config::resolve() takes the same parameters and raises the same error:

use Suqo\Config;

$config = Config::resolve(apiKey: $candidate);   // throws SuqoConfigError if bad

Logging

Diagnostics go to STDERR, so they never contaminate STDOUT in a CLI program. There is no logger injection point: set logLevel (or $SUQO_LOG) and the SDK builds its own.

$suqo = new SuqoClient(logLevel: 'debug');
// [suqo] debug request {"method":"GET","url":"https://…/api/v1/products/","request_id":"…"}
// [suqo] debug response {"status":200,"request_id":"…","elapsed_ms":184}

The SDK logs request and response at debug, and retry at warn with the attempt number and delay. The API key is never a logged value.

Retries and timeouts

GET requests are retried up to maxRetries times — three attempts by default — on a network failure, a timeout, a 429 or a 5xx. Backoff is full jitter: a uniform draw across [0, cap) with cap = min(8000, 500 × 2 ** attempt) milliseconds. A server-supplied Retry-After wins, is not jittered, and is capped at 60 seconds.

Writes are not retried, pending idempotency keys — see Not yet implemented.

Every attempt carries a fresh X-Request-Id, so a retry has a new id. Quote the one on the error in a support ticket:

catch (\Suqo\Exception\SuqoError $e) {
    error_log("suqo {$e->status} req={$e->requestId}: {$e->getMessage()}");
}

The key is sent on every request

Authorization: Bearer <key> goes on every request the SDK makes. Two consequences worth reading before you change the transport: redirects are never followed, and TLS verification is yours to keep. Both are covered in Inject an HTTP client.

On this page