# API Overview
## Header File
```c
#include <synta.h>
```
The header is auto-generated by cbindgen from the Rust source. Include it
once; all types, constants, and function prototypes are in the global
namespace with the `Synta` prefix.
## Linking
```bash
# With pkg-config (recommended)
gcc myapp.c $(pkg-config --cflags --libs csynta) -o myapp
# With CMake
find_package(Synta REQUIRED)
target_link_libraries(myapp Synta::Synta)
# Manual
gcc myapp.c -I/path/to/include -L/path/to/lib -lcsynta -lpthread -ldl -lm -o myapp
```
## Encoding Rules
```c
typedef enum SyntaEncoding {
SyntaEncoding_Der = 0,
SyntaEncoding_Ber = 1,
SyntaEncoding_Cer = 2,
} SyntaEncoding;
```
Pass `SyntaEncoding_Der` for strict DER (X.509, CMS, PKCS formats).
Pass `SyntaEncoding_Ber` for lenient BER parsing.
## Error Model
Every function that can fail returns `SyntaErrorCode`. On failure:
1. The return value is a non-zero `SyntaErrorCode`.
2. A detailed message is stored in thread-local storage and can be retrieved
with `synta_get_last_error_message()`.
Functions that return a pointer (e.g. `synta_decoder_new`,
`synta_certificate_parse_der`) return `NULL` on failure.
```c
SyntaCertificate *cert = synta_certificate_parse_der(data, len);
if (!cert) {
fprintf(stderr, "Parse error: %s\n", synta_get_last_error_message());
return -1;
}
```
See [Errors](errors.md) for the full error code table and error functions.
## Thread Safety
- **Encoder / Decoder handles** — not thread-safe. Each thread must use its
own encoder and decoder instances.
- **Error messages** — thread-local. `synta_get_last_error_message()` and
`synta_clear_last_error()` are thread-safe between threads.
- **PKI handles** (`SyntaCertificate *`, `SyntaCrl *`, etc.) — read-only
operations (getters) are thread-safe after construction; mutations require
external synchronization.
- **Helper functions** (`synta_oid_*`, `synta_integer_*`, etc.) — thread-safe
for read-only operations; mutations require external synchronization.
## Core Types
| `SyntaDecoder *` | Opaque decoder handle |
| `SyntaEncoder *` | Opaque encoder handle |
| `SyntaByteArray` | Borrowed or owned byte slice (16 bytes: `data`, `len: uint32_t`, `owned: uint32_t`) |
| `SyntaDecoderConfig` | DoS-protection limits (max depth, elements, length; all `uintptr_t`) |
| `SyntaEncoding` | `SyntaEncoding_Der`, `SyntaEncoding_Ber`, `SyntaEncoding_Cer` |
| `SyntaErrorCode` | Return code; `SyntaErrorCode_Success == 0` |
| `SyntaInteger *` | Opaque arbitrary-precision integer |
| `SyntaOctetString *` | Opaque byte string |
| `SyntaObjectIdentifier *` | Opaque OID |
| `SyntaCertificate *` | Opaque parsed X.509 certificate |
| `SyntaCrl *` | Opaque parsed X.509 CRL (RFC 5280 §5) |
| `SyntaCsr *` | Opaque parsed PKCS#10 CSR (RFC 2986) |
| `SyntaOcsp *` | Opaque parsed OCSP response (RFC 6960) |
| `SyntaDerList *` | Opaque list of DER byte vectors (PEM decode result) |
| `SyntaCmsContentInfo *` | Opaque CMS ContentInfo handle |
## SyntaByteArray
`SyntaByteArray` is a 16-byte struct:
```c
typedef struct {
const uint8_t *data;
uint32_t len;
uint32_t owned; /* 0 = borrowed, non-zero = owned */
} SyntaByteArray;
```
When `owned != 0`, the caller must call `synta_byte_array_free()` to release
the allocation. When `owned == 0`, the bytes are borrowed from a parent
object (e.g. a decoded certificate) and must not be freed independently.
```c
SyntaByteArray ba = {0};
if (synta_certificate_get_subject_der(cert, &ba) == SyntaErrorCode_Success) {
/* ba.owned == 0: borrowed, valid while cert is alive */
process(ba.data, ba.len);
/* do NOT call synta_byte_array_free(&ba) */
}
```
See [Memory Management](../memory.md) for the full ownership model.