Stream API
ABI Version: 1 · Header: c_api/c_api.h · Library: libapiexec.so / libapiexec_capi.a
ABI Stability Contract
ABI Freeze Point
c_api.h is the ABI freeze point. After the initial release, any change to
function signatures, struct layouts, or error code values requires a new
versioned symbol (e.g. stream_next_batch_v2). Callers must not invoke a
function whose ABI version they did not compile against.
APIEXEC_ABI_VERSIONis an integer constant in the header. Check it at compile time if you link against a potentially different version.- Struct layouts use explicit padding. No C++ types cross this boundary.
- All functions use C linkage (
extern "C").
Ownership Model
One allocation path, one free path
stream_destroy() is the only valid way to release a StreamHandle.
Calling free() directly is undefined behaviour.
stream_create()returns a heap-allocatedStreamHandle*. The caller owns this handle.- All buffers passed to
stream_next_*are caller-allocated. The C API never allocates caller-visible memory. stream_destroy(NULL)andstream_cancel(NULL)are safe no-ops.
Null-Safety Guarantees
Every pointer parameter is null-checked before dereference:
| Function | NULL handle | NULL buffer | NULL out param |
|---|---|---|---|
stream_create | n/a | n/a | n/a |
stream_destroy | no-op | n/a | n/a |
stream_has_next | STREAM_ERROR_INVALID_ARG | n/a | n/a |
stream_next_batch_v1 | STREAM_ERROR_INVALID_ARG | STREAM_ERROR_INVALID_ARG | STREAM_ERROR_INVALID_ARG |
stream_next_v2_ts | STREAM_ERROR_INVALID_ARG | n/a | STREAM_ERROR_INVALID_ARG |
stream_next_v2_sc | STREAM_ERROR_INVALID_ARG | STREAM_ERROR_INVALID_ARG | n/a |
stream_cancel | no-op | n/a | n/a |
Error Code Table
| Code | Value | Meaning |
|---|---|---|
STREAM_OK | 0 | Success |
STREAM_EXHAUSTED | 1 | No more data - normal termination |
STREAM_ERROR_RATE_LIMIT | -1 | 429 rate limited (retries exhausted) |
STREAM_ERROR_SERVER | -2 | 5xx server error (retries exhausted) |
STREAM_ERROR_CLIENT | -3 | 4xx non-429, or buffer too small |
STREAM_ERROR_PARSE | -4 | Response parse failure |
STREAM_ERROR_NETWORK | -5 | Network error (retries exhausted) |
STREAM_ERROR_CANCELLED | -6 | Stream was cancelled |
STREAM_ERROR_INVALID_ARG | -7 | NULL pointer or invalid argument |
Function Reference
stream_create
StreamHandle* stream_create(const char* adapter, const char* config_json, const char* policy_json);
Creates a new stream. Returns NULL on failure (bad config JSON, unknown
adapter, or allocation failure).
adapterconst char*requiredRegistered adapter name, e.g. "datadog-v1", "datadog-v2-ts",
"page-rest". Must match a name registered with StreamRegistry.
config_jsonconst char*requiredJSON object with adapter-specific configuration (API keys, query, time range, etc.). The library copies this - do not hold the pointer after the call.
policy_jsonconst char*optionalExecution policy overrides as JSON. Pass NULL for library defaults
(3 retries, 1 s initial backoff, prefetch depth 1).
stream_destroy
void stream_destroy(StreamHandle* handle);
Releases all resources associated with the handle. Safe to call with NULL.
After this call, handle is invalid - do not dereference it.
stream_has_next
int32_t stream_has_next(StreamHandle* handle);
Returns 1 if more data is available, 0 if the stream is exhausted, or
STREAM_ERROR_INVALID_ARG if handle is NULL.
handleStreamHandle*requiredA live handle returned by stream_create.
stream_next_batch_v1
int32_t stream_next_batch_v1(StreamHandle* handle, void* buf, int32_t buf_len, int32_t* out_count);
Fetches the next batch as a null-terminated JSON array into buf. Blocks
until data is available or an error occurs.
handleStreamHandle*requiredA live handle.
bufvoid*requiredCaller-allocated buffer. The library writes a null-terminated JSON array string into it.
buf_lenint32_trequiredSize of buf in bytes. If the batch does not fit, returns
STREAM_ERROR_CLIENT and the stream position is unchanged - safe to
retry with a larger buffer.
out_countint32_t*requiredSet to the number of records in the batch on STREAM_OK.
stream_next_v2_ts
int32_t stream_next_v2_ts(StreamHandle* handle, int64_t* out_ts_ms);
Fetches the epoch timestamp (milliseconds) of the next v2 timeseries record.
handleStreamHandle*requiredout_ts_msint64_t*requiredSet to the timestamp in milliseconds since Unix epoch on STREAM_OK.
stream_next_v2_sc
int32_t stream_next_v2_sc(StreamHandle* handle, char* out_buf, int32_t buf_len);
Fetches the next v2 scalar record as a null-terminated JSON string.
handleStreamHandle*requiredout_bufchar*requiredbuf_lenint32_trequiredout_buf in bytes.stream_cancel
void stream_cancel(StreamHandle* handle);
Signals the stream to stop. Thread-safe - the only call on a handle that
may be made from a different thread than the one calling stream_next_*.
Subsequent stream_next_* calls return STREAM_ERROR_CANCELLED. Safe to
call with NULL.
Threading
Handles are not thread-safe
Concurrent access to the same handle from multiple threads requires external
synchronisation - with the single exception of stream_cancel(), which is
explicitly safe to call from any thread.
Each stream owns its own transport connection and prefetch thread.
stream_cancel() uses an atomic flag internally; no lock is required on the
caller side.
