Skip to content

Wire Protocol

The Command-Array Format

SDK abstracts this away

You don't need to understand the wire protocol to use the SDK—it handles everything automatically. This page is for developers who want to understand what's happening under the hood or build custom integrations.

The Authentic8 API does not use standard REST endpoints. Every API call is a POST to a single endpoint with a JSON array payload — the command-array format.

POST /api/ HTTP/1.1
Host: extapi.authentic8.com
Content-Type: application/json

[
  {"command": "setauth", "data": "your_api_token"},
  {"command": "listusers", "org": "my_org"}
]
users = UserManagementAPI(config)
result = users.list_users("my_org")

The SDK constructs the array, adds the setauth command automatically, sends the request, and returns only the result you care about — you never see the array structure.

Request Structure

Every request body is a JSON array with at least two items:

[
  {"command": "setauth", "data": "TOKEN"},           // index 0: always required
  {"command": "wire_command", "param1": "value1"}    // index 1: params go FLAT alongside "command"
]

Params are flat — never nested under data

Command parameters go directly alongside "command" in the same object. They are not nested under a "data" key. The only "data" key in the array is on the setauth entry (which holds the token string).

// CORRECT:
{"command": "org.get", "org_name": "myorg"}

// WRONG:
{"command": "org.get", "data": {"org_name": "myorg"}}

Exception: create_context uses "context_data" (not "data") for session parameters, with max_uses at the command level.

setauth authenticates the session for all subsequent commands in the same array. Additional commands can be appended at indexes 2, 3, etc., but the SDK always sends exactly two commands per request (one setauth + one wire command).

Response Structure

The response is a parallel JSON array:

[
  {"result": "setting auth from data"},   // index 0: setauth acknowledgment
  {"result": {...}}                        // index 1: your command's result
]

Always read from response[1]["result"] — index 0 is the setauth ack, never the useful data.

The SDK's _extract_api_result(response, index=1) does this automatically.

Example: Full Round-Trip

# SDK call:
context_id = browsing.create_context(
    url="https://secure.example.com",
    username="analyst@company.com",
    policy=[{"type": "readonly", "params": ["true"]}],
    max_uses=1,
)

# Wire payload sent:
# [
#   {"command": "setauth", "data": "admin_token_value"},
#   {
#     "command": "create_context",
#     "context_data": {
#       "user": "analyst@company.com",
#       "urls": ["https://secure.example.com"],
#       "policy": [{"type": "readonly", "params": ["true"]}]
#     },
#     "max_uses": 1
#   }
# ]
# Note: create_context uses "context_data" nesting (not "data").
# Params "user" and "urls" (array) differ from the Python method's
# "username" and "url" parameter names.

# Wire response received:
# [
#   {"result": "setting auth from data"},
#   {"result": {"browse_context_id": "a1b2c3d4e5f6", "expires": 1735689600, "max_uses": 1}}
# ]

# SDK returns: "a1b2c3d4e5f6"
print(context_id)  # a1b2c3d4e5f6

Implication for Postman Testing

Because all API calls POST to the same endpoint, Postman tests follow a consistent pattern:

// Every post-response test script starts the same way:
pm.test("Response is command-array (≥2 items)", () => {
    pm.expect(pm.response.json()).to.be.an('array').with.lengthOf.at.least(2);
});

pm.test("Auth acknowledged at index 0", () => {
    pm.expect(pm.response.json()[0]?.result).to.include('setting auth');
});

// Then extract the actual result:
const result = pm.response.json()[1]?.result;

Non-Command-Array Endpoints

Two endpoints use different protocols and are not part of the command-array format:

File Download — POST /getfile/

POST https://extapi.authentic8.com/getfile/
Content-Type: multipart/form-data

id=<file_id>&auth=<file_token>

The response body is the raw file binary. There is no JSON wrapper. The SDK's FileAPI.download_file() handles this transparently.

File Upload — POST /putfile/

POST https://extapi.authentic8.com/putfile/
Content-Type: multipart/form-data

file=<binary>&name=<filename>&path=<dest_path>&bucket_id=<bucket_id>

Note: the form field is name (not dest_name) and path (not dest_path).

Context Shorthand — GET /ctx/

A single-step alternative to the two-step create → launch flow:

GET https://extapi.authentic8.com/ctx/
    ?auth=<admin_token>
    &user=<username>
    &url=<target_url>
    &response=url

The response parameter controls the return format:

Value Returns
redirect (default) HTTP redirect into the Silo browser session
url Launch URL as plain text — useful for automation and scripting
id Just the context launch ID as plain text

Use response=url or response=id when calling from scripts or Newman, since a redirect cannot be followed programmatically.

Proxy Policy Commands

Proxy policy management uses the standard command-array format but deserves special attention due to its unique response behavior and object schema.

Commands

// Read current proxy objects
{"command": "policy_proxies.get", "org_name": "MyOrg", "include_proxy_policy": true}

// Replace the entire proxy list (empty list clears all)
{"command": "policy_proxies.set", "org_name": "MyOrg", "proxies": [...]}

// Append proxies without replacing existing ones — multiple in a single call
{"command": "policy_proxies.add", "org_name": "MyOrg",
 "proxies": [{"name": "proxy1", ...}, {"name": "proxy2", ...}]}

// Remove proxies by name — multiple names in a single call
{"command": "policy_proxies.delete", "org_name": "MyOrg",
 "proxy_names": ["proxy1", "proxy2", "proxy3"]}

Proxy Object Schema

{
  "name": "eng_proxy_1",
  "location": {
    "address": "131.131.131.131",
    "port": 8080,
    "type": "http"
  }
}
Field Required Notes
name Yes Must be unique within the org's proxy list
location.address Yes IP address or FQDN
location.port No Defaults per type (HTTP→80, HTTPS→443, SOCKS→1080)
location.type No http (default), https, socks, socks4, socks5

HTTPS proxy certificate requirement

When type is https, the address value must exactly match the Common Name (CN) in the proxy server's SSL certificate. A mismatch causes ERR_PROXY_CERTIFICATE_INVALID for end users.

SOCKS authentication

SOCKSv4 supports no proxy authentication. SOCKSv5 supports no authentication in Chrome.

Delete Response

policy_proxies.delete always returns HTTP 200 with a result dict — it never returns an error even when named proxies do not exist:

{"proxies_deleted": ["proxy1"], "proxies_not_found": ["ghost"]}

Always check proxies_not_found explicitly in your application logic.

Hierarchy Aggregation

Proxy policies aggregate down the org hierarchy. Child orgs inherit and accumulate the proxy objects defined at every parent level. Setting or adding proxies at one org level does not affect parent or sibling orgs.

Why This Design?

The command-array protocol lets the Authentic8 platform execute multiple commands atomically in a single HTTP round-trip. While the SDK always uses one-command-per-request, the wire format supports batching for platform-internal operations.