API Requests
Record completed API requests as built-in Events through Coryn.addApiRequest() or the optional OkHttp interceptor. No State Provider registration is needed.
Call Coryn.init() and start recording before reporting requests. Requests outside an active recording are not buffered for a future session. This API and the built-in OkHttp interceptor are included in the upcoming 1.1.123 SDK; use the same version for all Coryn dependencies.
Manual reporting
Use this with any HTTP client, or when your app already has request instrumentation:
import ai.coryn.replay.api.core.main.Coryn
Coryn.addApiRequest(
endpoint = "https://example.com/orders",
method = "POST",
durationMs = 240L,
headers = mapOf("Content-Type" to listOf("application/json")),
body = """{"productId":42}""",
urlParams = mapOf("include" to listOf("items", "delivery")),
responseCode = 201,
responseBody = """{"orderId":"order-42"}""",
startedAtUnixMs = requestStartedAtUnixMs,
truncation = null // This instrumentation supplies complete data.
)
requestStartedAtUnixMs is the wall-clock start timestamp captured by your instrumentation. Omit it to infer the start from the call time minus durationMs. The Event is recorded when Coryn.addApiRequest() is called; the start timestamp and duration are metadata only. Negative durations are treated as zero.
For failures without an HTTP response, omit responseCode and provide error. For HTTP errors such as 401 or 503, provide the status code as usual. The SDK does not retry, cancel, or interpret these client requests.
Coryn.addApiRequest() accepts these arguments:
| Field | Meaning |
|---|---|
endpoint, method, durationMs | Required endpoint, HTTP method and execution duration in milliseconds. Method is normalised to uppercase. |
headers, urlParams, responseHeaders | Maps of names to lists, preserving repeated values. |
body, responseBody | Optional text payloads. |
responseCode | Optional HTTP status code. |
error | Optional transport failure description. |
startedAtUnixMs | Optional request start in Unix milliseconds. |
requestBodySizeBytes, responseBodySizeBytes | Optional body sizes. A client may report -1 for unknown length. |
truncation | Optional CorynApiRequestTruncation?, default UNKNOWN. Use TRUNCATED when your instrumentation already discarded data because of size limits, UNKNOWN when completeness is uncertain, or null when it verified that supplied data is complete. |
Snapshot and size limits
Reporting is thread-safe. Do not modify supplied collections while addApiRequest() is running. Changes made after the call returns do not affect the recorded data.
Reports retain at most 16,384 text characters in total, 8,192 per string, 64 entries per map, and 16 values per entry. Data beyond these limits may be omitted. Coryn reports TRUNCATED if it removes data because of size limits, even when the caller supplied UNKNOWN or null. Intentional redaction or omission does not imply truncation. API requests also share the State/Event limits; avoid reporting them at an unbounded rate.
Java overloads
Java callers can omit trailing optional arguments. Overloads cover the three required arguments through the full argument list. Omitting truncation uses CorynApiRequestTruncation.UNKNOWN, just as in Kotlin. The final parameter accepts CorynApiRequestTruncation.TRUNCATED, CorynApiRequestTruncation.UNKNOWN, or Java null:
import ai.coryn.replay.api.core.main.Coryn;
import java.util.Collections;
Coryn.addApiRequest("https://example.com/products", "GET", 120L);
Coryn.addApiRequest(
"https://example.com/orders", "POST", 240L,
Collections.singletonMap("Content-Type", Collections.singletonList("application/json")),
"{\"productId\":42}"
);
OkHttp integration
The interceptor is included in API core, also available through either recorder dependency. No extra Coryn module is needed. Add it explicitly to the OkHttp clients you want to observe. Only requests that start during active recording are eligible; reports submitted after recording stops are ignored.
Apps using the interceptor must declare an OkHttp dependency if they do not already have one:
dependencies {
implementation("com.squareup.okhttp3:okhttp:4.12.0")
}
Manual request reporting does not require adding OkHttp to your app's compile dependencies.
Add one application interceptor to each client you want to observe, after Coryn initialisation:
import ai.coryn.replay.api.core.main.Coryn
import okhttp3.OkHttpClient
val client = OkHttpClient.Builder()
.addInterceptor(Coryn.createApiRequestStateProviderOkHttpInterceptor())
.build()
Use addInterceptor, not addNetworkInterceptor. Each invocation reports one logical call, including OkHttp's redirects and retries. It records the original endpoint and method, response code and headers, known body sizes, start time, and duration until response headers arrive or transport fails. Duration does not include consuming the response body. A transport failure records its exception class and rethrows the original exception; HTTP errors return the original response normally.
Place it before other application interceptors if their short-circuited responses should also be recorded. Do not report the same call manually as well, unless you intentionally want two Events.
Bodies and redaction
Bodies are disabled by default. Enable them only for suitable clients and data:
val interceptor = Coryn.createApiRequestStateProviderOkHttpInterceptor(
captureRequestBody = true,
captureResponseBody = true,
redactedHeaders = setOf("X-Customer-Id"),
skippedHeaders = setOf("X-Debug-Trace"),
redactedUrlParameters = setOf("account_id"),
skippedUrlParameters = setOf("debug"),
transformRequest = { request ->
if (request.url.encodedPath == "/health") null
else request
},
transformResponse = { response ->
response.newBuilder().removeHeader("X-Session-Secret").build()
}
)
The four rule sets extend the built-in privacy rules:
| Option | Effect |
|---|---|
redactedHeaders | Keep matching request and response header names, replacing their values with <redacted>. |
skippedHeaders | Omit matching request and response headers entirely. |
redactedUrlParameters | Keep matching query parameter names, replacing all repeated values with <redacted>. |
skippedUrlParameters | Omit matching query parameters entirely. |
Matching is case-insensitive. Skipping takes precedence over redaction, including built-in redaction. Rule sets are copied when creating the interceptor; mutating the original sets does not change an existing interceptor.
Use transformRequest returning null to skip an endpoint. The capture flags omit request or response bodies. For path parameters, app-specific JSON fields and other data, the transforms can return sanitised diagnostic copies instead of modifying the real network exchange.
transformRequest and transformResponse receive OkHttp objects for diagnostic reporting. Return modified copies to redact additional data, or null to skip the Event. Only transformRequest runs for transport failures without a response. The original request sent by OkHttp and the response returned to your caller remain unchanged. Do not consume or close their bodies in these callbacks; use copies with replacement bodies for redaction, or keep body capture disabled. Exceptions in reporting or these callbacks do not replace the host call's response or transport exception.
- Request previews require a repeatable, non-duplex, textual body with a known length no larger than 8,192 bytes. Streaming, one-shot, unknown-length, oversized and binary request bodies are omitted. A repeatable request body may be serialised twice when capture is enabled.
- Textual response previews retain up to 8,192 bytes using a non-consuming peek. Peeking can read ahead and wait for bytes; leave it disabled for streaming APIs. Event streams, NDJSON and JSON-sequence bodies are skipped. Other custom streaming formats need app filtering or disabled response previews.
- Skipped bodies are omitted from the report. Incomplete previews report
TRUNCATED; uncertain completeness reportsUNKNOWN. Unsupported bodies and bodies disabled by configuration do not imply truncation. - Standard
Authorization,Proxy-Authorization,Cookie,Set-CookieandX-API-Keyheaders are replaced with<redacted>. Common secret query names (access_token,token,api_key,apikey,key,password,secret) are redacted case-insensitively. URL username, password and fragment are omitted; query parameters are recorded separately.
UI hiding does not redact network Events. The manual API records the values you supply without automatic redaction. The interceptor's built-in redaction list cannot identify every app-specific secret, personal field or path parameter. Remove sensitive data with the diagnostic transforms, omit bodies, or skip those endpoints before enabling this in production.
Demo
In CorynReplayDemoApp, open Mixed and tap Simulate API requests to try manual reporting, interception, failures and redaction. The sample uses synthetic responses and does not contact an external server.