IDkPlusClient exposes the complete DK Plus v1 Swagger areas for permissions, product inventory, vendors, vendor invoices, and warehouses. Public consumers use DevOp-owned models; the raw DK Plus vendor transport shape remains internal.
| Resource | Purpose |
|---|---|
client.Permission |
Reads module state and detailed access granted to the current API token. |
client.Inventory |
Creates inventory journals, warehouse transfers, and physical inventory counts. |
client.Purchase.Vendor |
Reads, searches, creates, and updates vendors (DkPlusVendor) and reads vendor transactions. The portable IExternalErpClient.Purchase.Vendor exposes the lean Vendor read model under ErpCapability.Vendors. |
client.Purchase.Invoice |
Reads processed/unprocessed invoices and attachments, creates invoices, and updates current-user approval. |
client.Warehouse |
Lists warehouses and updates a product's warehouse settings. |
All methods accept a CancellationToken. HTTP failures use the normal DkPlusRequestException hierarchy. Request models are validated before network I/O; for example, transfer and inventory-count item codes are required, and vendor addresses support at most four ordered lines.
var permissions = await client.Permission.GetCurrentAsync(cancellationToken);
if (permissions?.Vendors?.Invoices is PermissionAccess.Full or PermissionAccess.Modify)
{
// The token may perform the intended vendor-invoice operation.
}
Permission values are strongly typed as PermissionModuleState and PermissionAccess. JSON output retains unknown future fields in AdditionalData where available. On a vendor, the nested Approvers, Dimensions, Expenses, Delivery, BankAccount, and PaymentBankAccount objects each keep their own unknown members in their own AdditionalData; a write sends them back inside the same object, drops null values, and never lets an entry shadow a typed member.
CLI:
devop-dk permission show
devop-dk permission show --json
Vendor addresses use the shared Address model and ordered Lines, not provider-specific Address1 through Address4 properties. The portable Vendor read model holds only Number, Name, NationalId, Balance, and the shared lifecycle members; DkPlusVendor adds the address, contact numbers, commercial defaults, VatExempt, PayablesAccount, Approvers, BankAccount, Dimensions, Expenses, Delivery, Memos, and Attachments. Writes use VendorCreateRequest (full document, Number required) and VendorUpdateRequest (sparse; the vendor number is the path argument):
await client.Purchase.Vendor.CreateAsync(new VendorCreateRequest
{
Number = "V-100",
Name = "Example supplier",
NationalId = "0000000000",
Address = new Address
{
Lines = ["Example street 1", "Accounts payable"],
PostalCode = "101",
City = "Reykjavik",
CountryCode = "IS"
},
Email = "[email protected]",
CurrencyCode = "ISK",
Dimensions = new VendorDimensions { Dimension1 = "10" }
}, cancellationToken);
await client.Purchase.Vendor.UpdateAsync(
"V-100",
new VendorUpdateRequest { Blocked = true },
cancellationToken);
var transactions = await client.Purchase.Vendor.Transaction.GetPageAsync(
new VendorTransactionQuery
{
Vendor = "V-100",
Page = 1,
Count = 100,
ModifiedAfter = lastImport,
Sort = "Modified",
SortDirection = VendorTransactionSortDirection.Ascending
},
cancellationToken);
Sort = "Modified" and ModifiedAfter on a vendor transaction query use the transaction's Modified. Vendors themselves (VendorFilter.ModifiedAfter/ModifiedBefore, VendorPageRequest.ModifiedAfter, CLI purchase vendor list --modified-after) carry an ObjectDate, the dkPlus stored time, and DK Plus pages and applies that window on ObjectDate; DkPlusVendor.Modified is the dkERP modification time. See Upgrading to 0.4.
The CLI reads the same public shapes from JSON. vendor create --file deserializes a VendorCreateRequest; vendor update <number> --file deserializes a sparse VendorUpdateRequest that does not contain the vendor number:
{
"number": "V-100",
"name": "Example supplier",
"nationalId": "0000000000",
"address": {
"lines": ["Example street 1", "Accounts payable"],
"postalCode": "101",
"city": "Reykjavik",
"countryCode": "IS"
},
"email": "[email protected]",
"currencyCode": "ISK",
"dimensions": { "dimension1": "10" }
}
Read output (--json) is the flat DkPlusVendor shape with public names: nested objects such as dimensions.dimension1, bankAccount, and approvers rather than the DK Plus Dimmentions, BankInfo, Dim1, and Approve. See Models and writes for the sparse-update rules.
devop-dk purchase vendor list --modified-after 2026-10-01T00:00:00Z
devop-dk purchase vendor get V-100
devop-dk purchase vendor search "Example supplier" --maximum 25
devop-dk purchase vendor transactions --vendor V-100 --page 1 --count 100
devop-dk purchase vendor transactions-for V-100 --page 1 --count 100
devop-dk purchase vendor create --file ./vendor.json
devop-dk purchase vendor update V-100 --file ./vendor.json
Create requests use VendorInvoiceCreateRequest with VendorInvoiceLineRequest lines, while reads return VendorInvoice:
var request = new VendorInvoiceCreateRequest
{
Number = "SUPPLIER-INV-42",
Date = DateTimeOffset.UtcNow,
Amount = 12500m,
CurrencyCode = "ISK",
InvoiceType = VendorInvoiceType.Debit,
Lines =
[
new VendorInvoiceLineRequest
{
Account = "4000",
Text = "Professional services",
Type = VendorInvoiceLineType.Expenses,
Amount = 12500m
}
]
};
var created = await client.Purchase.Invoice.CreateAsync(
"V-100",
request,
cancellationToken);
Equivalent CLI JSON:
{
"number": "SUPPLIER-INV-42",
"amount": 12500,
"currencyCode": "ISK",
"invoiceType": "Debit",
"lines": [
{
"account": "4000",
"text": "Professional services",
"type": "Expenses",
"amount": 12500
}
]
}
The client maps VendorInvoiceType.Debit to the API's documented Debet wire value. CLI JSON uses the public enum name Debit.
Vendor-invoice and vendor-transaction --json output uses camel-case public names derived from the models, not DK Plus wire names: for example id (not ID), dimension1 (not Dim1), and the approval status Unapproved (not UnApproved). Scripts written against the previous output keys must be updated. Since 0.4.0 the numeric vendor-transaction enum fields (JournalHeadType, Origin, Code, TransactionType, RecordType, PaymentSlip, PaymentStatus) read as their documented names (for example Debit or Credit for TransactionType) instead of digits; JournalType stays numeric because its order is not confirmed. Attachments are FileAttachment values (FileName and Content); an attachment response that lacks a name or content raises DkPlusContractException (the response body is not retained), and Files on a create request carries the same type.
devop-dk purchase invoice processed --vendor V-100 --count 25
devop-dk purchase invoice get 123 --json
devop-dk purchase invoice my-approved
devop-dk purchase invoice my-unapproved
devop-dk purchase invoice unprocessed
devop-dk purchase invoice create V-100 --file ./vendor-invoice.json --yes
Approval updates use a separate request file:
{
"approvalAction": 1,
"description": "Approved after review",
"reference": "CASE-42"
}
devop-dk purchase invoice approval 123 --file ./approval.json --yes
Download attachments without overwriting existing files unless --force is supplied:
devop-dk purchase invoice attachment 123 --output ./documents/vendor-123.pdf
devop-dk purchase invoice unprocessed-attachment 456 --output ./documents/vendor-456.pdf
Without --output, the attachment is saved in the current directory under the last segment of the DK Plus file name, sanitized to letters, digits, -, _, and .; a name such as ../../x becomes x, and a name that is empty after sanitizing becomes vendor-invoice-<id>.bin. The file is never written outside the current directory.
Inventory writes are application-significant mutations and are never retried automatically. The CLI requires --yes. This differs from warehouse update-product below, which only changes a product's settings and runs without --yes.
Transfer JSON is an array:
[
{
"itemCode": "ITEM-1",
"fromWarehouse": "MAIN",
"toWarehouse": "OUTLET",
"quantity": 5,
"comment": "Stock replenishment"
}
]
devop-dk inventory transfer \
--file ./transfers.json \
--description "Stock replenishment" \
--post \
--yes
Journal JSON uses description and a lines array. Physical-count JSON uses description and lines containing itemCode, counted, and warehouse:
devop-dk inventory journal --file ./journal.json --yes
devop-dk inventory count --file ./count.json --yes
var warehouses = await client.Warehouse.GetAllAsync(cancellationToken);
await client.Warehouse.UpdateProductAsync(
"MAIN",
"ITEM-1",
new ProductWarehouseSettingsRequest
{
MinimumStock = 5,
MaximumStock = 50,
Location = "A-12",
DefaultPurchaseQuantity = 10,
SkipPurchaseOrderSuggestions = false
},
cancellationToken);
UpdateProductAsync takes ProductWarehouseSettingsRequest, the same type used for Warehouses in a product create or update request, and sends only the writable settings. Stock quantities (QuantityInStock, QuantityOnBackOrders, QuantityOnPurchaseOrders) and Modified are read-only and have no member; change stock through client.Inventory journals or counts. Null members are omitted, including a null Variations list; an explicit empty list is sent as []. Before 0.4.0 the method took the ProductWarehouse read model (now removed, together with WarehouseProductVariation) and sent its stock quantities, Modified, and an always-present "Variations":[]. See Upgrading to 0.4 for the full list.
CLI:
devop-dk warehouse list
devop-dk warehouse update-product MAIN ITEM-1 \
--file ./warehouse-product.json
The file is a ProductWarehouseSettingsRequest document:
{
"MinimumStock": 5,
"MaximumStock": 50,
"Location": "A-12",
"DefaultPurchaseQuantity": 10,
"SkipPurchaseOrderSuggestions": false
}
A file saved from the earlier warehouse-product shape is rejected on stderr with exit code 2 before any request: QuantityInStock, QuantityOnBackOrders, QuantityOnPurchaseOrders/QuantityPoOrders, and variation Quantity/QuantityOnBackOrders name inventory journal or inventory count as the replacement, Modified is read-only, and the wire spellings LocationInWarehouse, DefaultPOQuantity, SkipPOSuggestion, and variation Code2/Description2 name Location, DefaultPurchaseQuantity, SkipPurchaseOrderSuggestions, SecondaryCode, and SecondaryDescription.
The JSON file for update-product uses the public ProductWarehouseSettingsRequest property names; unknown keys other than those above are forwarded to DK Plus through AdditionalData. Add --json to read commands when output will be consumed by another program.