Article Import API
DRE exposes three distinct article-import paths. Choose the right one for your integration:
| Path | Service | Mode | Use When |
|---|---|---|---|
POST /pos/articles/import | POSService | Sync | POS terminal, small batches, immediate result needed |
POST /pos/articles/import-batch | POSService | Async | POS-originated batches > 50 articles; monitor via ArticleImportJobs |
POST /api/v1/Articles:bulk-import | PublicAPI | Async | System integrations, large volumes (up to 10 000 rows); monitor via ImportJobs |
The three paths above are for application-level article uploads. SAP S/4HANA
master data (article/merchandise views) replicates into DRE over a separate
DRFOUT inbound interface, not these endpoints. It terminates the
ProductMerchandiseViewReplicationBulkRequest contract via REST at
POST /api/v1/master-data/ProductMerchandiseViewReplicationBulkRequest
and via native SOAP at /api/v1/master-data/soap.
Auth is mTLS only. For the full envelope, field mapping, and onboarding, see the
DRFOUT Master Data guide.
For any import submitted via POST /api/v1/Articles:bulk-import (or any other
bulkImport bound action on PublicAPI), poll GET /api/v1/ImportJobs/{id} for
status — not ArticleImportJobs. See ImportJobs
below.
GET /api/v1/ArticleImportJobs and GET /api/v1/ArticleImportJobItems track
POS-originated batch imports (POST /pos/articles/import-batch) only. They are
deprecated (@deprecated). For all PublicAPI
bulk imports use ImportJobs + ImportJobErrors instead.
POST /api/v1/Articles:bulk-import — PublicAPI Bulk Import (canonical)
The bulkImport action is bound on every PublicAPI writable entity that supports
mass-create / mass-upsert: Articles, Promotions, Budgets, Stakeholders,
CouponTypes, CouponCodeConfigurations, CouponCodes, Conditions, ArticleGroups,
PosGroups, PriorityGroups, MutualExclusionGroups (12 entities; each has a
/<Entity>/PublicAPI.bulkImport path in the OpenAPI spec). This matches the
multi-type set tracked by ImportJobs below.
This section documents the request body schema in full, so integrators do
not have to reverse-engineer the shape from $metadata.
The Articles List Report upload button is not this endpoint. The Articles List Report toolbar has an
importArticlescustom action (a FileUploader dialog). It accepts CSV or JSON, parses the rows client-side, and POSTs them row-by-row to/admin/Articles— it is the end-user UI path, not the bulk-import API. The actual PublicAPI bulk import endpoint is documented here.
Endpoint
POST /api/v1/<Entity>:bulk-import (REST alias — recommended)
POST /api/v1/<Entity>/PublicAPI.bulkImport (OData V4 collection-bound)
| Header | Value |
|---|---|
Content-Type | application/json |
Authorization | Bearer <xsuaa-jwt> |
Idempotency-Key | client-generated UUID — RECOMMENDED |
Request body
{
header?: {
tenantId?: string; // override JWT tenant (admin scope only)
minorVersion?: integer; // wire-format version
continueOnError?: boolean; // false (default) = rollback on first error
idempotencyKey?: string; // alternative to Idempotency-Key header
},
rows: Array<EntityPayload>; // per-call cap: 10 000 rows
}
Each rows[] element uses the same JSON shape as a single
POST /api/v1/<Entity> body. See the generated OpenAPI spec for the
per-entity field list.
Example — Articles (3 rows)
POST /api/v1/Articles:bulk-import
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
Idempotency-Key: a1b2c3d4-1234-5678-9abc-def012345678
Content-Type: application/json
{
"header": {
"tenantId": "tenant-a",
"continueOnError": false
},
"rows": [
{ "articleNumber": "ART-1001", "name": "Espresso 1kg", "ean": "4001234567890" },
{ "articleNumber": "ART-1002", "name": "Filter Coffee 500g", "ean": "4001234567906" },
{ "articleNumber": "ART-1003", "name": "Decaf 250g", "ean": "4001234567913" }
]
}
Response (202 Accepted)
{
"jobId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"statusUrl": "/api/v1/ImportJobs(f47ac10b-58cc-4372-a567-0e02b2c3d479)",
"minorVersion": 13
}
Poll GET statusUrl (i.e. GET /api/v1/ImportJobs({id}) — the canonical
tracking entity documented below) until the job status is SUCCEEDED or
FAILED. With continueOnError: true the completed job lists per-row
outcomes via ImportJobErrors.
Idempotency-Key
Sending the same key twice within 24 hours returns the original
jobId (200) without re-running the import. Required for at-least-once
integrations where the client may retry on network failure.
Per-tenant limits
| Limit | Value |
|---|---|
| Rows per call | 10 000 |
Idempotency-Key retention | 24 h |
See also: Public API Service for auth headers, error catalog, HMAC sample, and OpenAPI links.
ImportJobs + ImportJobErrors
ImportJobs is the canonical status-tracking entity for all PublicAPI bulk
imports. It is multi-type: it tracks Articles, Promotions, Budgets, and
every other entity with a bulkImport bound action.
GET /api/v1/ImportJobs — list all jobs for current tenant
GET /api/v1/ImportJobs({id}) — single job status
GET /api/v1/ImportJobErrors?$filter=job_ID eq '{id}' — per-row errors
PATCH /api/v1/ImportJobs({id}) — update callbackUrl only
DELETE /api/v1/ImportJobs({id}) — allowed for terminal jobs only (409 if still running)
POS Article Import Paths
POST /pos/articles/import
Synchronous import. Returns immediately with per-article results. Use for real-time POS terminal scenarios where the operator needs instant feedback.
POST /pos/articles/import-batch
Asynchronous batch import. Returns a jobId for monitoring. Progress is tracked via
GET /admin/ArticleImportJobs({id}) (Admin Service) or
GET /api/v1/ArticleImportJobs({id}) (PublicAPI).
ArticleImportJobs / ArticleImportJobItems track POS-originated batch imports
only (POST /pos/articles/import-batch). They do not track PublicAPI bulk imports.
These entities are deprecated for new integrations — use ImportJobs for all
new PublicAPI integrations.