Synqony.Api.Sdk 1.5.0

dotnet add package Synqony.Api.Sdk --version 1.5.0
                    
NuGet\Install-Package Synqony.Api.Sdk -Version 1.5.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Synqony.Api.Sdk" Version="1.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Synqony.Api.Sdk" Version="1.5.0" />
                    
Directory.Packages.props
<PackageReference Include="Synqony.Api.Sdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Synqony.Api.Sdk --version 1.5.0
                    
#r "nuget: Synqony.Api.Sdk, 1.5.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Synqony.Api.Sdk@1.5.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Synqony.Api.Sdk&version=1.5.0
                    
Install as a Cake Addin
#tool nuget:?package=Synqony.Api.Sdk&version=1.5.0
                    
Install as a Cake Tool

Synqony.Api.Sdk

.NET SDK that abstracts HTTP communication with a Synqony API backend. Built on top of Synqony.Api.Model, it exposes a strongly-typed SynqonyApiClient that handles authentication, request serialization, and response parsing so consumers can interact with the API through plain C# methods.

Table of Contents


Installation

The package is available on nuget.org:

dotnet add package Synqony.Api.Sdk

Supported Frameworks: net10.0, net8.0


Quick Start

using Synqony.Api.Sdk;

using var httpClient = new HttpClient();

var config = new SynqonyApiConfig(
    baseUrl:      "https://api.synqony.com",
    clientId:     "<client-id>",
    clientSecret: "<client-secret>",
    context:      "<mandant-or-partnership-id>");

var client = SynqonyApiClient.ForClientCredentials(config, httpClient);

// Load a single address
var address = await client.Addresses.GetById("133716247126412");

// Load a paginated list
var firstPage = await client.Orders.GetList(pageNumber: 0, pageSize: 50);

The client transparently obtains an OAuth access token, attaches it to every request, serializes payloads to JSON, and deserializes responses into the strongly-typed Result<T> / ListInfo<T> wrappers from Synqony.Api.Model.


Architecture

SynqonyApiClient                  # Top-level facade — entry point
├── Addresses, Contacts           # Master data clients
├── Containers, ContainerTypes
├── Services, Vehicles, Drivers, Personnel
├── Orders, Contracts             # Transactional data clients
├── Invoices, CashJournals
├── Requisitions, StorageTransactions
└── Users, Permissions, Logs      # General clients
        │
        ▼
SynqonyApiHandler                 # Low-level HTTP send/receive + JSON
        │
        ▼
HttpClient + ITokenProvider     # Pluggable transport and auth
  • SynqonyApiClient – User-facing facade. Bundles all resource clients.
  • Resource clients (e.g. AddressesClient) – Implement marker interfaces (IGetById<T>, IGetList<T>, ICreate<T>, IUpdate<T>, IDelete<T>) that unlock matching extension methods.
  • SynqonyApiHandler – Wraps HttpClient and exposes typed GetAsync<T>, PostAsync<T>, PutAsync<T>, PatchAsync<T>, DeleteAsync<T> helpers. Handles bearer-token injection, JSON (de)serialization, and structured logging.
  • ITokenProvider – Abstraction over token retrieval. The default OAuthTokenProvider performs the Client Credentials flow; you can plug in a custom implementation (e.g. for the Password or Refresh Token flow, or to share a token cache across clients).

Configuration

SynqonyApiConfig carries everything the SDK needs to talk to a backend:

Property Description
BaseUrl Base URL of the Synqony API server. Trailing / is stripped automatically.
ClientId OAuth client id of the API user.
ClientSecret OAuth client secret of the API user.
Context Authorization context — typically a mandant number or partnership id.
var config = new SynqonyApiConfig(
    baseUrl:      "http://localhost:8084",
    clientId:     "my-client",
    clientSecret: "s3cret",
    context:      "100");

Authentication

The auth mode is always chosen explicitly through a named factory:

// OAuth Client Credentials, console logger
SynqonyApiClient.ForClientCredentials(config, httpClient);

// OAuth Client Credentials, custom logger factory
SynqonyApiClient.ForClientCredentials(config, httpClient, loggerFactory);

// OAuth Password (user credentials) flow with automatic refresh
SynqonyApiClient.ForUser(config, httpClient, username, password, scope, loggerFactory);

// Fully custom token provider (e.g. cached tokens, mocks)
new SynqonyApiClient(config, httpClient, tokenProvider, loggerFactory);

To implement a custom token provider, implement ITokenProvider:

public sealed class MyTokenProvider : ITokenProvider
{
    public Task<string> GetToken(CancellationToken cancellationToken = default)
        => Task.FromResult("<access-token>");
}

GetToken is invoked on every request, so caching/refreshing is the provider's responsibility. The built-in OAuthTokenProvider caches the token until it expires.


Resource Clients

Each resource client maps to a top-level API resource and is reachable via a property on SynqonyApiClient. Some resources expose entity-scoped sub-clients for navigating relationships, accessed through an indexer:

// All contact persons linked to a specific address
var linked = await client.Addresses["133716247126412"].Contacts.GetList();

CRUD Operations

CRUD methods are exposed as extension methods on marker interfaces. A resource client only offers the operations matching the interfaces it implements — calls to unsupported operations won't compile.

using Synqony.Api.Sdk.Clients;

// GET /addresses/{id}
Result<ApiAddress>? single = await client.Addresses.GetById(id);

// GET /addresses/:query?pageNo=0&pageSize=50
Result<ListInfo<ApiAddress>>? page = await client.Addresses.GetList(0, 50);

// POST /addresses/:query  (with filters and sort in the body)
var request = new ListRequestInfo
{
    Filters =
    {
        new ColumnFilter
        {
            ColumnName  = nameof(ApiContactPerson.Email),
            ColumnValue = "some.name@synqony.com",
            Operation   = EnumApiFilterOperation.Equal,
        },
    },
};
Result<ListInfo<ApiContactPerson>>? matches = await client.Contacts.GetList(request);

// POST /addresses
Result<ApiAddress>? created = await client.Addresses.Create(newAddress);

// PUT /addresses/{id}
Result<ApiAddress>? updated = await client.Addresses.Update(modifiedAddress);

// DELETE /addresses/{id}
Result<ApiAddress>? deleted = await client.Addresses.Delete(id);

All responses are wrapped in Result<T> and may contain status Messages in addition to (or instead of) Data. See Synqony.Api.Model for details on common types.

Marker Interfaces

Interface Unlocks
IGetById<T> GetById(id, ct)
IGetListBasic<T> GetList(pageNumber, pageSize, ct) (GET, query string)
IGetListFull<T> GetList(ListRequestInfo, ct) (POST, body)
IGetList<T> Both variants above
ICreate<T> Create(payload, ct)
IUpdate<T> Update(payload, ct) (requires T : IId)
IDelete<T> Delete(id, ct)
IResolve<TQuery, TResult> Resolve(query, ct) (POST body, :resolve custom method)

Service Capabilities

A service capability rule declares whether a service is supported at an address or a storage location — e.g. which materials a disposer accepts, or which waste codes a storage bay may store. The reason a service is or isn't supported is a business decision and out of the SDK's scope; the SDK only lets you maintain the rules and resolve against them.

The two concerns are deliberately separate:

  • Maintenance is ordinary CRUD on the rules, scoped to the owning entity. The owner is implied by the path, so the rule payloads (ApiAddressServiceCapability, ApiStorageLocationServiceCapability) do not repeat it.
  • Resolution answers "which entities match these criteria" and is exposed as a :resolve custom method (via IResolve<TQuery, TResult>) that returns full DTOs.

Maintaining rules (CRUD)

Reached through the entity-scoped indexer, mirroring Addresses[id].Contacts. Both owners expose an identical ServiceCapabilities sub-client with full CRUD:

// GET  /addresses/{id}/service_capabilities/:query?pageNo=0&pageSize=50
var rules = await client.Addresses[addressId].ServiceCapabilities.GetList(0, 50);

// POST /addresses/{id}/service_capabilities
await client.Addresses[addressId].ServiceCapabilities.Create(new ApiAddressServiceCapability
{
    Service   = new LinkableEntity(ResourceType.Services) { ForeignKey = serviceId },
    Mode      = EnumServiceHandlingMode.DropOff, // customer brings the material to this address
    IsAllowed = true,
});

// Same surface for storage locations (uses LegalCode instead of Mode)
await client.StorageLocations[locationId].ServiceCapabilities.Create(new ApiStorageLocationServiceCapability
{
    Service   = new LinkableEntity(ResourceType.Services) { ForeignKey = serviceId },
    LegalCode = "170405",
    IsAllowed = true,
});

Resolving

Wildcard rules, priorities and allow/deny are evaluated server-side; the result may contain several equally-suitable matches.

// "Which addresses support this service?"
// POST /addresses/:resolve
Result<ListInfo<ApiAddress>>? addresses = await client.Addresses.Resolve(
    new ApiAddressServiceCapabilityQuery
    {
        Service = serviceId,
        Mode    = EnumServiceHandlingMode.DropOff,
    });

// "Which storage locations accept this service / waste code?"
// POST /storage_locations/:resolve
Result<ListInfo<ApiStorageLocation>>? locations = await client.StorageLocations.Resolve(
    new ApiStorageLocationServiceCapabilityQuery { Service = serviceId, LegalCode = "170405" });

Resolution roots on the top-level collection that it returns, which keeps it distinct from the service_capabilities maintenance path and from plain listing (:query).


Payment Configuration

How payments can be accepted in the current scope. Read-only — a connection is set up by an administrator in the ERP. Each provider is addressed by its own sub-resource, so there is no list and no id:

// GET /payment_configurations/sumup
Result<ApiPaymentConfigurationSumUp>? configuration =
    await client.PaymentConfigurations.GetSumUpConfigurationAsync();

The backend answers 404 while SumUp is not set up for the scope — treat that as "no card payment here", not as an error. Offer card payment only when ActiveState is EnumActiveState.Active, and treat every other value — including one this package does not know yet — as not usable.

To talk to the provider itself, ask for a short-lived token. The request carries no payload; the credentials it is exchanged for stay on the server:

// POST /payment_configurations/sumup/token:create
Result<ApiPaymentProviderToken>? token =
    await client.PaymentConfigurations.CreateSumUpTokenAsync();

Keep the token in memory or the platform keystore, never in logs or crash reports, and do not use it past ExpiresAt. Every call mints a fresh token, so two calls close together answer with two different tokens, both valid for their own full lifetime. Ask for one per payment rather than keeping one in reserve: a token fetched ahead of time may be close to expiry by the time it is used.


Logging

The SDK uses Microsoft.Extensions.Logging and emits structured log entries from SynqonyApiHandler:

Level Event
Debug Sending {method} {url} / Received {code} {phrase}
Trace Full request and response bodies
Warning Response body could not be parsed as the expected type

When no ILoggerFactory is supplied, the SDK falls back to a built-in ConsoleLoggerFactory that writes to standard output. For production, plug in your own factory (e.g. Serilog, NLog, Microsoft.Extensions.Logging.Console):

using var loggerFactory = LoggerFactory.Create(builder =>
    builder.AddConsole().SetMinimumLevel(LogLevel.Debug));

var client = SynqonyApiClient.ForClientCredentials(config, httpClient, loggerFactory);

Low-Level HTTP Access

For requests not yet covered by a resource client, you can use SynqonyApiHandler directly. It accepts any Uri, serializes the body, attaches the bearer token, and deserializes the response:

var handler = new SynqonyApiHandler(httpClient, tokenProvider, logger, serializerOptions);

Result<MyDto>? response = await handler.GetAsync<Result<MyDto>>(
    new Uri($"{config.BaseUrl}/v1/{config.Context}/custom/endpoint"));

SynqonyApiHandler provides GetAsync<T>, PostAsync<T>, PutAsync<T>, PatchAsync<T>, and DeleteAsync<T>.


See Also

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.5.0 78 9/24/2026
1.4.0 118 9/10/2026
1.3.0 124 7/13/2026
1.2.6 115 6/19/2026