# Overview

Synqly will provide SDKs for a number of languages, making it convenient and easy to interact with our API. Our SDKs are the preferred path for integrating with Synqly APIs, as they make it much easier to match types and browse available functionality. If a given language is not yet supported however, it is still possible to communicate with API endpoints directly via HTTPS calls.

This page contains links to all of Synqly's supported SDKs, each of which is hosted in it's own repository. Every SDK repository will contain a `README.md` file describing language-specific details of how to use the library. In addition, every repository will contain at least one example demonstrating how to use the SDK within an application.

SDK support for more languages is coming soon: let us know if there's one you'd like to see!

# Synqly Client SDKs

- [Go SDK + Examples](https://github.com/Synqly/go-sdk)
- [Python SDK + Examples](https://github.com/Synqly/python-sdk)
- [NodeJS SDK](https://www.npmjs.com/package/@synqly/client-sdk)
- [NodeJS SDK Example](https://github.com/Synqly/examples/tree/main/siem-connector/nodejs)


# Synqly Connect SDK

For interfacing with Connect UI:

- [Connect React SDK](https://www.npmjs.com/package/@synqly/connect-react-sdk)
- [NextJS Pages Router Example](https://github.com/Synqly/examples/tree/main/connect/nextjs-pages)


# Migrating to SDK 2.x

See also: [July 24, 2026 release notes](https://docs.synqly.com/changelog/2026-07-24#sdk-2x-migration-guides).

Synqly SDK 2.x adds the `meta` query parameter ([meta functions](https://docs.synqly.com/api-reference/meta-functions)) to **every** engine endpoint, so meta functions work uniformly across the API. Most endpoints are unaffected — only a specific set of create/update/action calls have a breaking signature change, detailed per language below. Older SDK versions are still supported, so upgrading is optional.

## Golang SDK

Go cannot express optional positional arguments, so adding `meta` is a breaking signature change on the affected endpoints. The good news: **the Go compiler flags every call site that needs updating** — there are no silent behavior changes, so a build-fix-rebuild loop reliably gets you to a clean state.

There are two change shapes. Adopting `meta` itself is always optional.

### Shape 1 — endpoints that gained a `request` argument

Endpoints that previously took **no request object** (reads, single-resource gets, and action endpoints) now take a positional `request *engine.<Op>Request`. Pass `nil` when you aren't using meta:


```go
// before
ep, err := client.Edr.GetEndpoint(ctx, id)
// after
ep, err := client.Edr.GetEndpoint(ctx, id, nil)

// opting in to meta:
m := "count"
ep, err := client.Edr.GetEndpoint(ctx, id, &engine.GetEndpointRequest{Meta: []*string{&m}})
```

This affects read/get/query/action endpoints across the connectors — for example `Edr.GetEndpoint`, `EndpointManagement.GetDevice`, `Identity.GetGroup` / `EnableUser` / `DisableUser`, `Notifications.GetMessage` / `ClearMessage`, `Ticketing.GetTicket` / `ListComments` / `DeleteComment`, `Vulnerabilities.GetScanStatus`, `Storage.DeleteFile`, `Assets.GetLabels` / `QueryAlerts`, and `Custom.Delete`. The compiler reports each one as "not enough arguments"; insert `nil` (before any `option.RequestOption` arguments).

### Shape 2 — create/update/post endpoints: body moves under `.Body`

Endpoints that took a request **body** (or a list/map body) now take a request **wrapper** that carries `meta` alongside the body under a `.Body` field. The wire format is unchanged — only the Go construction changes:


```go
// before
client.Ticketing.CreateTicket(ctx, &engine.CreateTicketRequest{Name: "Bug", ...})
// after
client.Ticketing.CreateTicket(ctx, &engine.CreateTicketRequestInput{
    Body: &engine.CreateTicketRequest{Name: "Bug", ...},
})

// list/map bodies wrap the same way:
client.Siem.PostEvents(ctx, events)
//  ->
client.Siem.PostEvents(ctx, &engine.PostSiemEventRequest{Body: events})
```

### Affected endpoints and their new request type

| Connector | Method | New request type (`.Body` holds the old argument) |
|  --- | --- | --- |
| `assets` | `CreateAsset` | `CreateDeviceRequestInput` |
| `assets` | `CreateDevices` | `CreateDevicesRequestInput` |
| `assets` | `CreateSoftware` | `CreateSoftwareInventoryRequestInput` |
| `assets` | `UpdateDeviceProperties` | `BulkUpdateDevicePropertiesRequestInput` |
| `edr` | `CreateIocs` | `CreateIocsRequestInput` |
| `edr` | `CreateThreatNote` | `CreateThreatNoteRequestInput` |
| `edr` | `ExecuteCommand` | `ExecuteCommandRequestInput` |
| `edr` | `NetworkQuarantine` | `NetworkQuarantineRequestInput` |
| `endpointmanagement` | `RemediateDevice` | `RemediationRequestInput` |
| `notifications` | `CreateMessage` | `CreateNotificationRequestInput` |
| `ticketing` | `CreateTicket` | `CreateTicketRequestInput` |
| `ticketing` | `CreateAttachment` | `CreateAttachmentRequestInput` |
| `ticketing` | `CreateComment` | `CreateCommentRequestInput` |
| `ticketing` | `CreateNote` | `CreateNoteRequestInput` |
| `ticketing` | `PatchTicket` | `PatchTicketRequestInput` |
| `ticketing` | `PatchNote` | `PatchNoteRequestInput` |
| `siem` | `PatchInvestigation` | `PatchInvestigationRequestInput` |
| `siem` | `PostEvents` | `PostSiemEventRequest` |
| `sink` | `PostEvents` | `PostSinkEventRequest` |
| `custom` | `Patch` | `PatchCustomRequestInput` |
| `custom` | `Post` | `PostCustomRequest` |
| `custom` | `PostBatch` | `PostBatchCustomRequest` |
| `vulnerabilities` | `CreateAsset` | `CreateAssetRequestInput` |
| `vulnerabilities` | `CreateFindings` | `CreateFindingsRequestInput` |
| `vulnerabilities` | `UpdateAsset` | `UpdateAssetRequestInput` |
| `vulnerabilities` | `UpdateFinding` | `UpdateFindingRequestInput` |
| `vulnerabilities` | `UploadScan` | `UploadScanRequestInput` |


In every case, wrap the value you used to pass in `&engine.<NewType>{Body: <old value>}`. To opt into meta, set `Meta: []*string{...}` on the wrapper. Note `vulnerabilities.CreateAsset` and `vulnerabilities.UpdateAsset` share the `CreateAssetRequest` body but use **different** wrappers (`CreateAssetRequestInput` vs `UpdateAssetRequestInput`); `assets.CreateAsset` is distinct again (`CreateDeviceRequestInput`).

### Recommended migration steps (Go)

1. **Upgrade the SDK and build.** `go build ./...` (and `go vet` / `go test` to include test files) flags every affected call site precisely.
2. **Apply the two patterns above** to each flagged site — insert `nil` for Shape 1, wrap the body for Shape 2 — and rebuild until green.
3. **Optional — use a coding agent.** Hand it this guide plus your repository and have it apply the changes, using your `go build` / tests as the completeness gate. The compiler catching every site makes this reliable.


We deliberately do not ship an automated codemod: a pattern-matching script mis-fires on identically-named methods (e.g. `slices.Delete`, other clients' `PostEvents`) and misses requests built into variables, whereas the compiler — or a compiler-guided coding agent — handles every case correctly.

## Python SDK

For the typed Python SDK this is **additive almost everywhere**. A small set of create/update operations have a breaking signature change. This guide is the complete list of what changed and how to update.

> This guide covers the **typed Python SDK** (`synqly`). If you use the **typeless** SDK (`synqly-typeless`), no changes are required — meta is added as an optional keyword argument and nothing else changes.


### Scope at a glance

- **No change needed** for the vast majority of endpoints — reads, queries, single-resource gets, actions, and the JSON-patch endpoints. They gain an optional `meta=` keyword argument you can ignore or adopt.
- **No change needed** if you already call create/update endpoints with flattened keyword arguments, or by spreading a request object's fields (`client.ticketing.create_ticket(**my_request.dict())`).
- **Breaking** only for the create/update operations listed below, and only if you pass a **request object** (`request=SomeRequest(...)`).


If your integration only reads data, upgrading is a no-op.

### The breaking change: request objects become keyword arguments

Adding `meta` changed these requests so the body is passed as **flattened keyword arguments** instead of a request object:


```python
# BEFORE
client.ticketing.create_ticket(request=CreateTicketRequest(name="Bug", summary="x"))

# AFTER — body fields become direct keyword arguments (plus an optional meta=)
client.ticketing.create_ticket(name="Bug", summary="x")
client.ticketing.create_ticket(name="Bug", summary="x", meta=["count"])
```

**To migrate:** drop the `request=SomeRequest(...)` wrapper and pass its fields directly as keyword arguments. Equivalently, `request=SomeRequest(**fields)` becomes `**fields`.

### Affected operations

| Connector | Operations |
|  --- | --- |
| `ticketing` | `create_ticket`, `create_attachment`, `create_comment`, `create_note` |
| `vulnerabilities` | `create_asset`, `update_asset`, `create_findings`, `update_finding` |
| `edr` | `create_iocs`, `network_quarantine` |
| `assets` | `create_asset` |
| `notifications` | `create_message` |


The JSON-patch operations (`patch_ticket`, `patch_note`, `patch_investigation`) keep their `request=` parameter and are **not** affected.

### Call styles that already work (no change)


```python
# flattened keyword arguments — already correct
client.ticketing.create_ticket(name="Bug", summary="x")
# spreading a request object's fields
client.ticketing.create_ticket(**my_ticket.dict())
# list-body / JSON-patch endpoints keep request=
client.siem.post_events(request=[event])
client.ticketing.patch_ticket(ticket_id, request=[{"op": "replace", ...}])
```

### Recommended migration steps (Python)

1. **Upgrade the SDK** and run your test suite and type checker (mypy / pyright). Each breaking call surfaces as a clear type error pointing at the exact line; there are no silent behavior changes.
2. **Update the flagged calls** using the pattern above — at most the handful of operations in the table, most projects use only a few.
3. **Optional — use a coding agent.** Because the change is a uniform, well-scoped flatten on a known operation list, you can hand this guide and your repository to a coding assistant and have it apply the changes, using your test/type-check run as the completeness gate.


Adopting `meta` itself is always optional — every affected call also accepts an optional `meta=` argument when you want to invoke meta functions.