Gateman
Documentation/Canonical PHP client

Official Gateman PHP client

The official Gateman PHP client is a standalone implementation of the authenticated transport and authentication boundary defined by Contract v1. PHP, Node.js, Python, and Go are equally official Gateman clients.

Client version: 1.0.0.

Requirements and acquisition

The client requires PHP 8.3 or newer, cURL, and JSON support. Sodium is required for Ed25519 signing. There is no Composer dependency.

Gateman distributes the standalone source file from:

GET https://getgateman.com/client/php

Acquire it during setup or deployment:

curl --fail --silent --show-error https://getgateman.com/client/php -o gateman.php

Then include it from server-side PHP:

require_once __DIR__ . '/gateman.php';

This is public PHP artifact acquisition. It is distinct from authenticated POST /client/get, which returns application integration context.

Configuration

The client reads process environment variables. It does not load .env files.

VariableRequiredMeaning
GM_BASE_URLyesGateman URL using http or https
GM_APPyesApplication identifier
GM_APP_SECRETHMACApplication secret
GM_PRIVATE_KEYEd25519Canonical Base64 raw 32-byte Ed25519 seed
APP_ENVIRONMENTselected routesproduction, staging, or development

GM_PRIVATE_KEY takes precedence over GM_APP_SECRET. Invalid key material is a local configuration error and never silently falls back to HMAC. The client does not choose an application environment.

Authenticated request

gm_request() sends one authenticated JSON POST and never retries. This example uses POST /client/get, which requires the application scope client:read:

require_once __DIR__ . '/gateman.php';
$result = gm_request('/client/get', []);
if ($result['error'] !== null) {
    throw new RuntimeException($result['error']['message']);
}
$status = $result['meta']['http_status'];
if (!is_int($status) || $status < 200 || $status >= 300) {
    throw new RuntimeException('Gateman returned HTTP ' . (string)$status);
}
$integrationContext = $result['body'];

The values above are application code, not a fabricated response. Capability payloads remain defined by their individual Gateman contracts.

Public API

gm_request(string $path, array $payload = [], ?string $idempotencyKey = null, ?string $credentialRequestId = null): array

The path must begin with /. Queries, fragments, controls, whitespace, Unicode, backslashes, dot segments, and transport-normalizing paths are rejected. Already percent-encoded transport-equivalent paths are accepted.

The payload is a PHP array. The optional idempotency key is trimmed around spaces and tabs, omitted when empty, limited to 255 bytes, and signed. It does not itself provide route-level idempotency.

For /secrets/get and /db/get, a fresh lowercase 32-hex-character credential-request ID is generated when omitted. A supplied ID must have that exact format.

gm_health(): array

Performs unauthenticated GET /health with a three-second timeout. Health does not prove application authorization or provider configuration.

gm_client_get(): array

Performs unauthenticated GET /client/php and returns the public PHP source artifact in body on a successful text/plain response. It does not call authenticated POST /client/get.

Environment handling

The client reads the application environment from APP_ENVIRONMENT. It accepts production, staging, and development, and trims and lowercases the value before use. Requests to routes that require an environment fail locally when the variable is missing or invalid; the normalized value is injected into the request payload automatically. See Contract v1 for the authoritative route classification.

If the payload already contains environment, its trimmed, lowercased value must match APP_ENVIRONMENT; a conflict is a local validation error. The caller’s original PHP array is not intentionally mutated. Environment- independent routes receive no automatic environment, and the client does not select an implicit default.

Result structure

Every received HTTP response, including non-2xx responses, is returned as:

[
    'body' => mixed,
    'raw_body' => ?string,
    'headers' => array<string, list<string>>,
    'meta' => [
        'http_status' => ?int,
        'gateman_request_id' => ?string,
        'retry_after' => ?int,
    ],
    'error' => ?array{kind: string, message: string},
]

Headers use lowercase names and preserve duplicate values as lists. Valid JSON is decoded into body. Non-JSON bodies remain in raw_body and set error.kind to decode. Transport, configuration, validation, encoding, and decoding failures are local errors; transport failures have no HTTP status.

Request IDs are exposed only when exactly 16 lowercase hexadecimal characters. Valid integer Retry-After values appear in meta.

Operational behavior

Authenticated requests use a one-second cURL connect timeout and ten-second total timeout. Health uses a one-second connect timeout and a three-second total timeout. Requests are synchronous and never retried automatically.

The shared signing and authentication rules are defined by Contract v1.