API reference

Client and worker SDKs

Install the Kiwi Distro client and worker SDKs for .NET, Java, Node.js and Python, configure them, and call the admin API from code.

Distro Current 4 min read Updated

Note

Kiwi Distro is currently in private preview. Interfaces and behaviour described here can change before general availability. Contact Kiwify Labs for access.

Kiwi Distro has a client SDK (call methods and use the admin API) and a worker SDK (implement methods) for .NET, Java, Node.js and Python. They follow the same wire contracts, Client protocol and Worker protocol.

Choose your language in any sample below. The choice applies to every sample on the site and is remembered in your browser.

Language Client SDK Worker SDK Requires
.NET Kiwify.Kiwi.Distro.Client.Native Kiwify.Kiwi.Distro.Worker .NET
Java kiwify-kiwi-distro-client kiwify-kiwi-distro-worker Java 17
Node.js @kiwify/kiwi-distro-client @kiwify/kiwi-distro-worker Node.js 22.18
Python kiwify-kiwi-distro-client kiwify-kiwi-distro-worker Python 3.11

The Java, Node.js and Python SDKs have no runtime dependencies beyond the language's standard library.

Note

The SDKs are not yet published to the public package registries. Build them from source as shown below, or ask Kiwify Labs for access.

Build and install#

Run these in the folder of the SDK you want (sdk/client/<language> or sdk/worker/<language>). In .NET, add a project reference instead.

.NET
dotnet add reference path/to/Kiwify.Kiwi.Distro.Client.Native/Kiwify.Kiwi.Distro.Client.Native.csproj
dotnet add reference path/to/Kiwify.Kiwi.Distro.Worker/Kiwify.Kiwi.Distro.Worker.csproj
Java
mvn package    # target/kiwify-kiwi-distro-client-0.1.0.jar (or ...-worker-0.1.0.jar)
Node.js
npm install    # dev dependencies only: TypeScript and the Node.js type definitions
npm test
Python
pip install .

Configure#

Client and worker settings resolve from lowest to highest precedence: appsettings.json, then KIWI_-prefixed environment variables, then --key value command-line arguments, then the values you pass in code. Every setting is described in Worker and client settings.

A client needs middleware_url, client_id and client_secret. A worker needs middleware_url and auth_secret. Set middleware_ca_url to pin the middleware's CA over TLS. Treat client secrets and worker secrets like passwords: keep them in a secret store, never in source control.

Connect a client#

.NET
using Kiwify.Kiwi.Distro.Client.Native.Core;

var factory = new MiddlewareClientFactory(middlewareUrl, middlewareCaUrl);
factory.CreateAuthProviderBuilder().SetClientCredentials(clientId, clientSecret).Build();
factory.CreateHttpBuilder().Build();
Java
KiwiClient client = KiwiClient.builder()
    .middlewareUrl(middlewareUrl)
    .middlewareCaUrl(middlewareCaUrl)   // optional
    .clientId(clientId).clientSecret(clientSecret)
    .connect();
Node.js
const client = await KiwiClient.connect({
  middlewareUrl, middlewareCaUrl, clientId, clientSecret,
});
Python
client = KiwiClient.connect(
    middleware_url=middleware_url,
    middleware_ca_url=middleware_ca_url,   # optional
    client_id=client_id,
    client_secret=client_secret,
)

Invoking methods is covered in Invoke methods from a client, and implementing them in Write a worker.

Use the admin API#

The client SDKs expose the admin API for services, clients, workers and worker profiles, secrets, sidecar mappings, scripts and executors, feedback and groups. For example, register a service, store a secret, attach it to the service and list its workers:

.NET
using Kiwify.Kiwi.Distro.Client.Models.Request;

var services = factory.CreateServiceAdmin();
var secrets = factory.CreateSecretsAdmin();
var workers = factory.CreateWorkerAdmin();

await secrets.StoreSecretAsync(new StoreSecretRequest
{
    SecretKey = "api-key", SecretType = "i", SecretValue = apiKeyValue,   // "i" internal, "x" external
});
await services.CreateServiceSecretsAsync(new ServiceSecretsRequest
{
    ServiceId = serviceId, Secrets = ["api-key"],
});
var list = await workers.GetAllWorkersAsync(new WorkerListRequest { ServiceId = serviceId });
Java
client.services().create(Map.of("service_name", "billing"));
client.secrets().store("api-key", apiKeyValue);                 // internal
client.services().addSecrets(serviceId, List.of("api-key"));
var workers = client.workers().list(Map.of("service_id", serviceId));
Node.js
await client.services.create({ service_name: "billing" });
await client.secrets.store("api-key", apiKeyValue);             // internal
await client.services.addSecrets(serviceId, ["api-key"]);
const workers = await client.workers.list({ service_id: serviceId });
Python
client.services.create({"service_name": "billing"})
client.secrets.store("api-key", api_key_value)                  # internal
client.services.add_secrets(service_id, ["api-key"])
workers = client.workers.list({"service_id": service_id})

To store an external secret, a reference your secrets resolver understands, pass the reference with the type x. Secrets attached to a service are delivered to its workers at registration.

Errors#

A transport, authentication or non-success HTTP failure is reported as an error: KiwiApiError (with status and body) in Node.js and Python, KiwiApiException in Java, and a failed Result in .NET. A method that ran and failed is not an error. It comes back with status: "failed" and an error message.