OpenAkeneo.RestApiClient
0.4.0
See the version list below for details.
dotnet add package OpenAkeneo.RestApiClient --version 0.4.0
NuGet\Install-Package OpenAkeneo.RestApiClient -Version 0.4.0
<PackageReference Include="OpenAkeneo.RestApiClient" Version="0.4.0" />
<PackageVersion Include="OpenAkeneo.RestApiClient" Version="0.4.0" />
<PackageReference Include="OpenAkeneo.RestApiClient" />
paket add OpenAkeneo.RestApiClient --version 0.4.0
#r "nuget: OpenAkeneo.RestApiClient, 0.4.0"
#:package OpenAkeneo.RestApiClient@0.4.0
#addin nuget:?package=OpenAkeneo.RestApiClient&version=0.4.0
#tool nuget:?package=OpenAkeneo.RestApiClient&version=0.4.0
OpenAkeneo.RestApiClient
Unofficial .NET client library for the Akeneo PIM REST API — typed models, automatic OAuth token management, streaming pagination, and Polly-based retry handling.
Note: This project is currently in development, APIs may change between minor versions until 1.0. Use at your own risk!
Note: Akeneo is a registered trademark of Akeneo SA. This project is not affiliated with Akeneo SA.
Note: This project was developed with assistance from AI tools. Please consider this fact against your AI governance policy before using this library.
Why this exists
Akeneo does not publish an official .NET SDK. The options available are either outdated, incomplete, or tightly coupled to specific project structures. This library was built to fill that gap — a clean, modern .NET client that handles the OAuth lifecycle, retries, and HAL pagination so you can focus on working with your PIM data rather than the HTTP layer.
Features
- Two-layer architecture: low-level HTTP service + high-level typed context
- Automatic OAuth token acquisition, in-memory caching, and proactive refresh at 75% of token lifetime
- Transparent 401 retry — fetches a new token and retries once without any extra code
IAsyncEnumerable<T>streaming for all list resources — handles pagination automatically- Polly resilience pipeline: 5 retries with exponential back-off, jitter, and
Retry-Aftersupport CancellationTokensupport on every method- Optional disk-based token cache for persistence across process restarts
Installation
dotnet add package OpenAkeneo.RestApiClient
Or search for OpenAkeneo.RestApiClient in the NuGet Package Manager.
Quickstart
// 1. Load settings
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false)
.Build();
var settings = configuration.GetSection("AkeneoSettings").Get<AkeneoRestApiSettings>();
// 2. Create the client
var context = new AkeneoContext(settings);
// 3. Use it
await foreach (var product in context.StreamProductUuidsAsync())
{
Console.WriteLine($"{product.Uuid} — enabled: {product.Enabled}");
}
Configuration
Copy appsettings.example.json to appsettings.json and fill in your credentials:
{
"AkeneoSettings": {
"Id": "MyConnection",
"Name": "My Akeneo Connection",
"ClientId": "your_client_id",
"ClientSecret": "your_client_secret",
"Username": "your_api_username",
"Password": "your_api_password",
"RestApiUrl": "https://your-instance.cloud.akeneo.com",
"TokenFilePath": ""
}
}
TokenFilePath is optional. When set (e.g. "akeneo_token.{0}.json"), the OAuth token is cached to disk and reused across restarts. Leave empty to cache in memory only.
Security note:
TokenFilePathshould point to a directory with restrictive ACLs. Never place it on a shared filesystem or in a web-accessible path.
Architecture
| Layer | Class | Responsibility |
|---|---|---|
| Low-level | AkeneoRestApiService |
OAuth, HTTP, retries, token cache |
| High-level | AkeneoContext |
Typed methods for all Akeneo resources |
For most use cases, only AkeneoContext is needed.
Dependency Injection (ASP.NET Core / hosted services)
For long-running applications, use AddAkeneoClient so IHttpClientFactory manages handler rotation, preventing stale-DNS and socket exhaustion:
// Program.cs
var settings = builder.Configuration.GetSection("AkeneoSettings").Get<AkeneoRestApiSettings>();
builder.Services.AddAkeneoClient(settings);
Then inject AkeneoContext into your services:
public class ProductSyncService
{
private readonly AkeneoContext _akeneo;
public ProductSyncService(AkeneoContext akeneo)
{
_akeneo = akeneo;
}
public async Task SyncAsync(CancellationToken ct)
{
await foreach (var product in _akeneo.StreamProductUuidsAsync(ct: ct))
{
// process product
}
}
}
For scripts and console apps where DI is not used, new AkeneoContext(settings) is the simpler option.
Usage
Token Management
Tokens are acquired automatically on the first call. Explicit control is also available:
var token = await context.Service.GetTokenAsync();
var freshToken = await context.Service.GetTokenAsync(forceRefresh: true);
Tokens are refreshed automatically at 75% of their lifetime. On a 401 Unauthorized response the service transparently fetches a new token and retries once.
Error Handling
All API errors throw AkeneoApiException:
try
{
var product = await context.GetProductUuidAsync("non-existent-uuid");
}
catch (AkeneoApiException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
Console.WriteLine($"Product not found: {ex.ApiMessage}");
}
catch (AkeneoApiException ex)
{
Console.WriteLine($"API error {ex.StatusCode} at {ex.RequestUrl}: {ex.ApiMessage}");
}
Pagination Patterns
Every list resource exposes three access patterns:
| Method | Description |
|---|---|
StreamXxxAsync() |
IAsyncEnumerable<T> — yields items one-by-one, fetches pages on demand. Best for large catalogs. |
GetXxxListAsync(page, limit) |
Returns a single page with HAL navigation links. |
GetXxxListFullAsync() |
Buffers all pages into a List<T>. Convenient but may use significant memory on large catalogs. |
Search Filter Syntax
Many list methods accept a search parameter. The value is a JSON-encoded Akeneo search filter following the Akeneo filter syntax:
// Products enabled in the ecommerce channel
var search = """{"enabled":[{"operator":"=","value":true}]}""";
// Products updated since a date
var search = """{"updated":[{"operator":">","value":"2024-01-01 00:00:00"}]}""";
// Products in a specific category (including children)
var search = """{"categories":[{"operator":"IN CHILDREN","value":["master"]}]}""";
// Attributes of a specific type
var search = """{"type":[{"operator":"IN","value":["pim_catalog_simpleselect","pim_catalog_multiselect"]}]}""";
The search value must be URL-safe JSON — the library handles encoding automatically.
System Information
var info = await context.GetSystemInformationAsync();
Console.WriteLine($"Akeneo version: {info.Version}, edition: {info.Edition}");
Products (UUID-based)
The preferred modern API uses product UUIDs.
// Stream all products
await foreach (var product in context.StreamProductUuidsAsync())
Console.WriteLine($"{product.Uuid} — enabled: {product.Enabled}");
// Stream with search filter, scoped to a channel with specific locales
var search = """{"enabled":[{"operator":"=","value":true}]}""";
await foreach (var product in context.StreamProductUuidsAsync(
search: search,
scope: "ecommerce",
locales: "en_US,fr_FR"))
{
Console.WriteLine(product.Uuid);
}
// Include CDN share links for asset_collection attribute values
await foreach (var product in context.StreamProductUuidsAsync(withAssetShareLinks: true))
{
// product.Values["my_asset_collection"][0].GetLinkedData<Dictionary<string, AssetCollectionLinkedDataEntry>>()
}
// Single product by UUID
var product = await context.GetProductUuidAsync("a4f47e32-b29c-4f3d-a0b2-123456789abc");
// Create or update (PATCH)
await context.CreateOrUpdateProductUuidAsync(new ProductUuid
{
Uuid = "a4f47e32-b29c-4f3d-a0b2-123456789abc",
Enabled = true,
Family = "clothing"
});
// Create (POST — returns the created product)
var created = await context.CreateProductUuidAsync(new ProductUuid
{
Family = "clothing",
Enabled = true
});
// Delete
await context.DeleteProductUuidAsync("a4f47e32-b29c-4f3d-a0b2-123456789abc");
// Submit for approval (requires Workflow feature)
await context.SubmitProductUuidProposalAsync("a4f47e32-b29c-4f3d-a0b2-123456789abc");
// Search product UUIDs (returns the matching UUIDs list resource)
var search = """{"enabled":[{"operator":"=","value":true}]}""";
var uuids = await context.SearchProductUuidsAsync(search: search);
// Upload a media file and get back the file code
var fileBytes = await File.ReadAllBytesAsync("image.jpg");
var fileCode = await context.UploadProductMediaFileAsync(fileBytes, "image.jpg", "image/jpeg");
// Draft (requires Workflow feature)
var draft = await context.GetProductUuidDraftAsync("a4f47e32-b29c-4f3d-a0b2-123456789abc");
Products (Identifier-based)
The legacy identifier (SKU) API is also fully supported.
await foreach (var product in context.StreamProductIdentifiersAsync())
Console.WriteLine(product.Identifier);
var product = await context.GetProductIdentifierAsync("my-sku-001");
await context.CreateOrUpdateProductIdentifierAsync(new ProductIdentifier
{
Identifier = "my-sku-001",
Family = "clothing",
Enabled = true
});
// Create (POST)
var created = await context.CreateProductIdentifierAsync(new ProductIdentifier
{
Identifier = "new-sku-002",
Family = "clothing"
});
// Delete
await context.DeleteProductIdentifierAsync("my-sku-001");
// Submit for approval (requires Workflow feature)
await context.SubmitProductIdentifierProposalAsync("my-sku-001");
var draft = await context.GetProductIdentifierDraftAsync("my-sku-001");
Reading Product Attribute Values
Product attribute values live in product.Values, keyed by attribute code. Each entry is a list of ProductValue objects (one per locale/scope combination).
var product = await context.GetProductUuidAsync("a4f47e32-b29c-4f3d-a0b2-123456789abc");
if (product.Values != null && product.Values.TryGetValue("name", out var nameValues))
{
// Get the en_US value (non-scopable attribute)
var enValue = nameValues.FirstOrDefault(v => v.Locale == "en_US");
Console.WriteLine(enValue?.GetStringData()); // returns string directly
}
// Numeric attribute
if (product.Values.TryGetValue("weight", out var weightValues))
{
var metric = weightValues.FirstOrDefault(v => v.Locale == null && v.Scope == null)
?.GetData<MetricValue>();
Console.WriteLine($"{metric?.Amount} {metric?.Unit}"); // e.g. "1.5 KILOGRAM"
}
// Boolean attribute
if (product.Values.TryGetValue("is_new", out var isNewValues))
{
bool? isNew = isNewValues.FirstOrDefault()?.GetData<bool>();
}
// Multiselect attribute (list of option codes)
if (product.Values.TryGetValue("color", out var colorValues))
{
var codes = colorValues.FirstOrDefault()?.GetData<List<string>>();
}
// Price collection
if (product.Values.TryGetValue("price", out var priceValues))
{
var prices = priceValues.FirstOrDefault()
?.GetData<List<Dictionary<string, object?>>>();
// Each dict has "amount" and "currency" keys
}
// Asset collection — get CDN share links (requires withAssetShareLinks: true)
if (product.Values.TryGetValue("packshots", out var assetValues))
{
var links = assetValues.FirstOrDefault()
?.GetLinkedData<Dictionary<string, AssetCollectionLinkedDataEntry>>();
foreach (var (assetCode, entry) in links ?? [])
foreach (var link in entry.ShareLinks ?? [])
Console.WriteLine($"{assetCode}: {link.Links?.Self?.Href}");
}
GetStringData() covers text, textarea, identifier, date, file, image, and simpleselect attributes. For all other types use GetData<T>() with the appropriate type.
Product Models
await foreach (var model in context.StreamProductModelsAsync())
Console.WriteLine($"{model.Code} — family: {model.Family}");
var model = await context.GetProductModelAsync("summer_collection_2024");
await context.CreateOrUpdateProductModelAsync(new ProductModel
{
Code = "summer_collection_2024",
Family = "clothing",
FamilyVariant = "clothing_color_size"
});
// Create (POST)
var created = await context.CreateProductModelAsync(new ProductModel
{
Code = "winter_2025",
Family = "clothing",
FamilyVariant = "clothing_color_size"
});
// Delete
await context.DeleteProductModelAsync("summer_collection_2024");
// Submit for approval (requires Workflow feature)
await context.SubmitProductModelProposalAsync("summer_collection_2024");
var draft = await context.GetProductModelDraftAsync("summer_collection_2024");
Product Media Files
await foreach (var file in context.StreamProductMediaFilesAsync())
Console.WriteLine($"{file.Code} — {file.MimeType}");
var fileMeta = await context.GetProductMediaFileAsync("f/f/c/f/ffcf2...125_image.jpg");
byte[] bytes = await context.DownloadProductMediaFileAsync("f/f/c/f/ffcf2...125_image.jpg");
File.WriteAllBytes("output.jpg", bytes);
Families & Variants
await foreach (var family in context.StreamFamiliesAsync())
Console.WriteLine(family.Code);
var family = await context.GetFamilyAsync("digital_cameras");
await context.CreateOrUpdateFamilyAsync(new Family
{
Code = "my_family",
AttributeAsLabel = "name",
Labels = new() { ["en_US"] = "My Family" }
});
// Create (POST)
var createdFamily = await context.CreateFamilyAsync(new Family
{
Code = "accessories",
AttributeAsLabel = "name"
});
await foreach (var variant in context.StreamFamilyVariantsAsync("clothing"))
Console.WriteLine(variant.Code);
var variant = await context.GetFamilyVariantAsync("clothing", "clothing_color_size");
await context.CreateOrUpdateFamilyVariantAsync("clothing", new FamilyVariant
{
Code = "clothing_color_size",
Labels = new() { ["en_US"] = "Color and size" }
});
// Create variant (POST)
var createdVariant = await context.CreateFamilyVariantAsync("clothing", new FamilyVariant
{
Code = "clothing_size_only",
Labels = new() { ["en_US"] = "Size only" }
});
Attributes
await foreach (var attr in context.StreamAttributesAsync())
Console.WriteLine($"{attr.Code} — {attr.Type}");
// With a type filter
var search = """{"type":[{"operator":"IN","value":["pim_catalog_simpleselect"]}]}""";
var selectAttrs = await context.GetAttributeListFullAsync(search: search);
// Include table select options (for pim_catalog_table attributes)
var tableAttrs = await context.GetAttributeListFullAsync(withTableSelectOptions: true);
var attr = await context.GetAttributeAsync("accessories_care_instructions");
await context.CreateOrUpdateAttributeAsync(new AkeneoAttribute
{
Code = "my_text_attr",
Type = "pim_catalog_text",
Group = "general"
});
// Create (POST)
var created = await context.CreateAttributeAsync(new AkeneoAttribute
{
Code = "launch_date",
Type = "pim_catalog_date",
Group = "marketing"
});
Attribute Options & Groups
// Options
await foreach (var option in context.StreamAttributeOptionsAsync("color"))
Console.WriteLine($"{option.Code}");
var options = await context.GetAttributeOptionListFullAsync("color");
var option = await context.GetAttributeOptionAsync("color", "red");
await context.CreateOrUpdateAttributeOptionAsync("color", new AttributeOption
{
Code = "navy",
Labels = new() { ["en_US"] = "Navy Blue" }
});
// Create option (POST)
var createdOption = await context.CreateAttributeOptionAsync("color", new AttributeOption
{
Code = "teal",
Labels = new() { ["en_US"] = "Teal" }
});
// Groups
await foreach (var group in context.StreamAttributeGroupsAsync())
Console.WriteLine(group.Code);
await context.CreateOrUpdateAttributeGroupAsync(new AttributeGroup
{
Code = "marketing",
Labels = new() { ["en_US"] = "Marketing" }
});
// Create group (POST)
var createdGroup = await context.CreateAttributeGroupAsync(new AttributeGroup
{
Code = "technical",
Labels = new() { ["en_US"] = "Technical" }
});
Categories
await foreach (var cat in context.StreamCategoriesAsync())
Console.WriteLine($"{cat.Code} — parent: {cat.Parent}");
// Include enriched attributes (category media, labels)
await foreach (var cat in context.StreamCategoriesAsync(withEnrichedAttributes: true))
Console.WriteLine(cat.Code);
var cat = await context.GetCategoryAsync("master");
await context.CreateOrUpdateCategoryAsync(new Category
{
Code = "sale",
Parent = "master",
Labels = new() { ["en_US"] = "Sale" }
});
// Create (POST)
var created = await context.CreateCategoryAsync(new Category
{
Code = "new_arrivals",
Parent = "master",
Labels = new() { ["en_US"] = "New Arrivals" }
});
// Upload a category media file
var imageBytes = await File.ReadAllBytesAsync("banner.png");
var fileCode = await context.UploadCategoryMediaFileAsync(imageBytes, "banner.png", "image/png");
byte[] bytes = await context.DownloadCategoryMediaFileAsync("c/7/3/c/c73cc4...ecf4_banner.png");
Channels, Locales, Currencies, Measurement Families
// Channels
var channels = await context.GetChannelListFullAsync();
var channel = await context.GetChannelAsync("ecommerce");
await context.CreateOrUpdateChannelAsync(new Channel { Code = "b2b", /* ... */ });
// Create channel (POST)
var created = await context.CreateChannelAsync(new Channel
{
Code = "mobile",
Locales = ["en_US"],
Currencies = ["USD"]
});
// Locales
var locales = await context.GetLocaleListFullAsync();
var locale = await context.GetLocaleAsync("en_US");
// Currencies
var currencies = await context.GetCurrencyListFullAsync();
var currency = await context.GetCurrencyAsync("USD");
// Measurement families (no paging — returns all at once)
var measurementFamilies = await context.GetMeasurementFamilyListAsync();
// Create or update measurement families (PATCH — returns raw response JSON)
var responseJson = await context.CreateOrUpdateMeasurementFamiliesAsync(new List<MeasurementFamily>
{
new() { Code = "CUSTOM_WEIGHT", StandardUnitCode = "GRAM" }
});
Association Types
var all = await context.GetAssociationTypeListFullAsync();
var assoc = await context.GetAssociationTypeAsync("x_sell");
await context.CreateOrUpdateAssociationTypeAsync(new AssociationType
{
Code = "bundle",
Labels = new() { ["en_US"] = "Bundle" }
});
// Create (POST)
var created = await context.CreateAssociationTypeAsync(new AssociationType
{
Code = "related",
Labels = new() { ["en_US"] = "Related" }
});
Reference Entities
// Entity definitions
var entities = await context.GetReferenceEntityListFullAsync();
var entity = await context.GetReferenceEntityAsync("brand");
await context.CreateOrUpdateReferenceEntityAsync(new ReferenceEntity { Code = "brand" });
// Entity attributes
var attributes = await context.GetReferenceEntityAttributeListAsync("brand");
var attribute = await context.GetReferenceEntityAttributeAsync("brand", "description");
await context.CreateOrUpdateReferenceEntityAttributeAsync("brand", new ReferenceEntityAttribute
{
Code = "description",
Type = "text"
});
// Attribute options
var options = await context.GetReferenceEntityAttributeOptionListAsync("brand", "country");
await context.CreateOrUpdateReferenceEntityAttributeOptionAsync("brand", "country",
new ReferenceEntityAttributeOption { Code = "se", Labels = new() { ["en_US"] = "Sweden" } });
// Records
await foreach (var record in context.StreamReferenceEntityRecordsAsync("brand"))
Console.WriteLine(record.Code);
var records = await context.GetReferenceEntityRecordListFullAsync("brand");
var record = await context.GetReferenceEntityRecordAsync("brand", "nike");
await context.CreateOrUpdateReferenceEntityRecordAsync("brand", new ReferenceEntityRecord
{
Code = "acme",
Values = new() { ["name"] = new() { new ReferenceEntityRecordValue { Data = "Acme Corp", Locale = "en_US" } } }
});
// Media files
byte[] bytes = await context.DownloadReferenceEntityMediaFileAsync("f/f/c/f/...logo.png");
// Upload a reference entity media file
var fileBytes = await File.ReadAllBytesAsync("logo.png");
var fileCode = await context.UploadReferenceEntityMediaFileAsync(fileBytes, "logo.png", "image/png");
Assets
// Asset families
var families = await context.GetAssetFamilyListFullAsync();
var family = await context.GetAssetFamilyAsync("packshots");
await context.CreateOrUpdateAssetFamilyAsync(new AssetFamily { Code = "packshots" });
// Asset family attributes
var attrs = await context.GetAssetAttributeListAsync("packshots");
var attr = await context.GetAssetAttributeAsync("packshots", "media_file");
await context.CreateOrUpdateAssetAttributeAsync("packshots", new AssetAttribute
{
Code = "alt_text",
Type = "text"
});
// Asset attribute options
var options = await context.GetAssetAttributeOptionListAsync("packshots", "orientation");
await context.CreateOrUpdateAssetAttributeOptionAsync("packshots", "orientation",
new AssetAttributeOption { Code = "landscape" });
// Assets within a family
await foreach (var asset in context.StreamAssetsAsync("packshots"))
Console.WriteLine(asset.Code);
var asset = await context.GetAssetAsync("packshots", "front_view");
await context.CreateOrUpdateAssetAsync("packshots", new Asset { Code = "front_view" });
// Download asset binary
byte[] bytes = await context.DownloadAssetMediaFileAsync("path/to/asset_file.jpg");
// Upload an asset media file
var fileBytes = await File.ReadAllBytesAsync("photo.jpg");
var fileCode = await context.UploadAssetMediaFileAsync(fileBytes, "photo.jpg", "image/jpeg");
Jobs
// List available jobs
var jobs = await context.GetJobListFullAsync();
var job = await context.GetJobAsync("csv_product_export");
// Launch export
var result = await context.LaunchExportJobAsync("csv_product_export");
Console.WriteLine($"Launched job execution #{result.JobExecutionId}");
// Dry run
var dryRun = await context.LaunchExportJobAsync("csv_product_export", isDryRun: true);
// Launch import
var importResult = await context.LaunchImportJobAsync("csv_product_import");
// Poll execution status
var execution = await context.GetJobExecutionAsync(result.JobExecutionId);
Console.WriteLine($"Status: {execution.Status}");
// Browse execution history
await foreach (var exec in context.StreamJobExecutionsAsync())
Console.WriteLine($"{exec.JobLabel} — {exec.Status}");
Workflows
// Workflow definitions
await foreach (var workflow in context.StreamWorkflowsAsync())
Console.WriteLine(workflow.Code);
var workflow = await context.GetWorkflowAsync("product_review");
// Workflow tasks (items awaiting action)
await foreach (var task in context.StreamWorkflowTasksAsync())
Console.WriteLine($"{task.Uuid} — {task.Status}");
// Include attribute values on tasks
var tasks = await context.GetWorkflowTaskListFullAsync(withAttributes: true);
var task = await context.GetWorkflowTaskAsync("task-uuid-here");
// Step assignees
var assignees = await context.GetWorkflowStepAssigneeListFullAsync("step-uuid-here");
Catalogs
// List catalogs
await foreach (var catalog in context.StreamCatalogsAsync())
Console.WriteLine($"{catalog.Id} — {catalog.Name}");
var catalog = await context.GetCatalogAsync("my-catalog-id");
// Stream all product UUIDs from a catalog
await foreach (var uuid in context.StreamCatalogProductUuidsAsync("my-catalog-id"))
Console.WriteLine(uuid);
// Stream full product objects from a catalog
await foreach (var product in context.StreamCatalogProductsAsync("my-catalog-id"))
Console.WriteLine(product.Uuid);
// Single product from catalog
var product = await context.GetCatalogProductAsync("my-catalog-id", "product-uuid");
// Mapped products (returns raw JSON string — use when catalog has a product mapping configured)
var mappedJson = await context.GetCatalogMappedProductListAsync("my-catalog-id");
var mappedModels = await context.GetCatalogMappedModelListAsync("my-catalog-id");
var mappedVars = await context.GetCatalogMappedVariantListAsync("my-catalog-id");
// Mapping schema
var schema = await context.GetCatalogMappingSchemaAsync("my-catalog-id");
// Create catalog (POST)
var created = await context.CreateCatalogAsync(new Catalog { Name = "B2B Catalog" });
// Update catalog (PATCH — returns updated catalog)
var updated = await context.UpdateCatalogAsync("my-catalog-id", new Catalog { Name = "Renamed" });
// Duplicate catalog
var copy = await context.DuplicateCatalogAsync("my-catalog-id");
// Set or delete mapping schema
var schemaJson = """{"properties":{"uuid":{"type":"string"}}}""";
await context.SetCatalogMappingSchemaAsync("my-catalog-id", schemaJson);
await context.DeleteCatalogMappingSchemaAsync("my-catalog-id");
// Delete catalog
await context.DeleteCatalogAsync("my-catalog-id");
Utilities
// System information
var info = await context.GetSystemInformationAsync();
Console.WriteLine($"Akeneo {info.Edition} {info.Version}");
// API overview (available endpoints)
var overview = await context.GetApiOverviewAsync();
// User channel and locale permissions
var channelPerms = await context.GetUserChannelsPermissionsAsync("user-uuid");
var localePerms = await context.GetUserLocalesPermissionsAsync("user-uuid");
// Extensions
await foreach (var ext in context.StreamExtensionsAsync())
Console.WriteLine(ext.Code);
// Modelization suggestions
var suggestions = await context.GetModelizationSuggestionListAsync();
var suggestion = await context.GetModelizationSuggestionAsync("suggestion-uuid");
Cancellation Token Support
Every method accepts an optional CancellationToken:
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
await foreach (var product in context.StreamProductUuidsAsync(ct: cts.Token))
Console.WriteLine(product.Uuid);
Resilience and Retries
AkeneoRestApiService uses a Polly resilience pipeline aligned with Akeneo's recommended retry strategy:
- 5 retries with exponential back-off starting at 500 ms, capped at 30 s, with jitter
- Handles
429 Too Many Requests,408 Request Timeout, transient5xxerrors, and network faults - Respects the
Retry-Afterresponse header automatically - Logs retries at
Warninglevel when a logger is provided
No additional configuration is required.
API Reference
Full Akeneo REST API documentation: api.akeneo.com
License
| Product | Versions 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 is compatible. 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 was computed. 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. |
-
net8.0
- Microsoft.Extensions.Configuration.Binder (>= 10.0.7)
- Microsoft.Extensions.Http.Resilience (>= 10.5.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.7)
-
net9.0
- Microsoft.Extensions.Configuration.Binder (>= 10.0.7)
- Microsoft.Extensions.Http.Resilience (>= 10.5.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.7)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.