🔒safe-tlsAPI Docs

API Reference

safe-tls exposes a minimal JSON API. Clients connect over HTTPS and the server captures the TLS ClientHello before responding, so every response reflects the capabilities of the exact connection that made the request.

Base URL

All endpoints are served over HTTPS on the configured address (default :8443). The UI and API share the same origin.

Authentication

No authentication is required. CORS is open (Access-Control-Allow-Origin: *).

Endpoints

GET/api/inspectInspect TLS ClientHello

Returns the full TLS analysis of the requesting connection — including ClientHello capabilities, fingerprints, grade, and the negotiated parameters. The observation is keyed by remote address and expires after 15 minutes.

Response — 200 application/json

FieldTypeDescription
observation*ObservationWhat the client advertised in its TLS ClientHello.
negotiated*NegotiatedConnectionParameters that were actually negotiated for this connection.

Observation object

captured_atstring (ISO 8601)Timestamp of the TLS handshake.
remote_addrstringIP address and port of the client.
server_namestring?SNI hostname sent by the client, if any.
offered_versionsProtocolVersion[]?TLS versions the client supports.
cipher_suitesIDName[]?Cipher suites advertised in the ClientHello.
supported_groupsSupportedGroup[]?Named groups / key exchange algorithms offered. Includes post-quantum flag.
signature_schemesIDName[]?Signature algorithms the client can verify.
alpnstring[]?Application protocols offered (e.g. h2, http/1.1).
fingerprintsFingerprints?JA3 and JA4 fingerprints — each has string and hash fields.
gradeGradeSecurity grade. Contains score (0–100), rating (A+…F), findings, and recommendations.
raw_client_helloRawClientHello?Verbatim parsed ClientHello record, including extensions, key shares, and ECH/certificate-compression flags.
limitationsstring[]?Any caveats that may have affected analysis accuracy.

NegotiatedConnection object

versionProtocolVersionTLS version that was negotiated.
cipher_suiteIDNameCipher suite selected by the server.
alpnstring?Application protocol negotiated via ALPN.
did_resumebooleanWhether this connection resumed a previous session.
server_namestring?SNI hostname as seen by the server.
mutual_tlsbooleanTrue if the client presented a certificate.
encrypted_client_helloboolean?True if ECH was accepted.
verified_atstring (ISO 8601)Timestamp of the API response.

Error responses

StatusCondition
400Request was made over plain HTTP, not HTTPS.
404No handshake observation found for this connection (e.g. connection was reused from an older session that has since expired).

Example response

{
  "observation": {
    "captured_at": "2026-04-20T12:00:00Z",
    "remote_addr": "203.0.113.42:54321",
    "server_name": "tls.example.com",
    "offered_versions": [
      { "id": 772, "hex": "0x0304", "name": "TLS 1.3", "status": "recommended" }
    ],
    "cipher_suites": [
      { "id": 4865, "hex": "0x1301", "name": "TLS_AES_128_GCM_SHA256", "status": "recommended" }
    ],
    "supported_groups": [
      { "id": 25497, "hex": "0x6399", "name": "X25519MLKEM768", "status": "recommended", "post_quantum": true }
    ],
    "signature_schemes": [
      { "id": 2052, "hex": "0x0804", "name": "rsa_pss_rsae_sha256", "status": "recommended" }
    ],
    "fingerprints": {
      "ja3":  { "string": "769,4865-4866,0-23-65281,...", "hash": "a1b2c3..." },
      "ja4":  { "string": "t13d1516h2_8daaf6152771...", "hash": "d4e5f6..." }
    },
    "grade": {
      "score": 95,
      "rating": "A+",
      "summary": "Excellent — post-quantum key exchange offered.",
      "post_quantum_offered": true,
      "findings": [],
      "recommendations": []
    }
  },
  "negotiated": {
    "version":      { "id": 772, "hex": "0x0304", "name": "TLS 1.3" },
    "cipher_suite": { "id": 4865, "hex": "0x1301", "name": "TLS_AES_128_GCM_SHA256" },
    "alpn":         "h2",
    "did_resume":   false,
    "server_name":  "tls.example.com",
    "mutual_tls":   false,
    "verified_at":  "2026-04-20T12:00:00Z"
  }
}

Usage from a REST client

Any HTTP client that performs its own TLS handshake can be inspected — curl, fetch, Go's http.Client, etc. If you are behind a corporate proxy that intercepts TLS you will see the proxy's ClientHello, not your own.

curl -sk /api/inspect | jq .