SUQODocs
User GuideAPI ReferenceSDKs
PHP SDK v1.0.0. This version is frozen and no longer updated. Read the latest (1.1.0).

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