AgentStack
SKILL verified MIT Self-run

S4hana Create Product

skill-ilia-inovaflow-s4hana-create-record-skills-s4hana-create-product · by ilia-inovaflow

Create product master records (materials) in SAP S/4HANA Cloud Public or on-prem private edition via OData V4 api_product/srvd_a2x/sap/product/0002 deep-insert. Use whenever the user wants to create, post, add, generate, seed, or onboard products / materials / SKUs — phrases like "create products in SAP", "seed material master", "add HAWA materials", "onboard FERT goods", "create a SERV record",…

No reviews yet
0 installs
0 views
view→install

Install

$ agentstack add skill-ilia-inovaflow-s4hana-create-record-skills-s4hana-create-product

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of S4hana Create Product? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

s4hana-create-product

Create product master (material) records on SAP S/4HANA Cloud Public. Verified production-ready against SAP S/4HANA Cloud Public Edition 2026-05-13 (10 products created via API: HAWA, FERT, SERV mix on my438741).

When to trigger

Verbs: create / post / add / generate / seed / onboard Objects: product(s), material(s), SKU(s), HAWA / FERT / SERV / ROH / HALB record(s) Counts: 1 to ~200 records.

Hard rules (never violate)

  1. Use OData V4, not the SOAP productmdmbulkreplicaterequest service. SOAP returns HTTP 202 but silently drops on Cloud Public tenants without MDG / sender-business-system registration. V4 is the supported create path.
  2. Always GET an existing product first to discover the tenant's internal unit codes (e.g. ST for Stück, LE for Leistungseinheit). V2 ISO-translates these (ST→PC); V4 does not. Mismatched UoM → MG/142 "value not allowed for MARM-MEINH".
  3. Deep-insert child must repeat parent's Product key in each _ProductDescription entry. SAP's SADL framework rejects inheritance — without explicit Product: in the child you get CMD_PROD_RAP/003 "Property PRODUCT is a key and cannot be initial".
  4. One-record probe before bulk (≥3 records).
  5. Never invent unit codes or product groups — verify against existing tenant data via GET first.
  6. Scripts go in /.s4hana-tmp/create-products-/. Never commit, never modify .env.
  7. POSTs are sequential with 200ms delay; halt on 3 consecutive failures.

Endpoint

  • Service path: /sap/opu/odata4/sap/api_product/srvd_a2x/sap/product/0002
  • Entity sets: Product, ProductDescription, ProductPlant, ProductSales, plus 20+ extension entities
  • Method: POST (deep-insert with _ProductDescription collection)
  • Communication scenario: SAP_COM_0009 — "Product Integration"

Phase 0 — Setup check (MANDATORY, no exceptions)

Before any API call, before any tool use, do this check. Even if you already know credentials from earlier in the conversation — IGNORE that knowledge and re-check from scratch each invocation.

  1. Announce: tell the user "Checking for SAP credentials in ``..."
  2. Check ONLY these two sources:
  • A .env file at ./.env (in the current working directory — NOT parent dirs, NOT ~/.env, NOT any memory file)
  • Shell-exported env vars: SAP_HOST AND SAP_AUTH_MODE both present
  1. If neither: auto-create ./.env from the bundled template (curl from https://raw.githubusercontent.com/ilia-inovaflow/s4hana-create-record-skills/main/.env.example), append .env to .gitignore if not already there, tell the user clearly what to fill in (auth mode + host + creds), and wait for them to say "ready" before making any API call. Never overwrite an existing .env.
  2. If credentials are present: report back to the user: "✓ Loaded credentials for ` in ` mode. Proceeding with [task]."

Never use credentials from conversation memory, from another project's .env, or from any tenant the user previously worked with in a different session. Each project gets its own .env. See [shared/setup-check.md](../../shared/setup-check.md) for the full rationale and edge cases.

Phase 1 — Parse user intent

Determine: count, ProductType mix (HAWA goods / FERT finished / SERV services / ROH raw / HALB semi-finished), whether external IDs should be supplied or auto-generated (the V4 service requires explicit Product field — there is no auto-numbering via API).

Ask one consolidated question if ambiguous:

  • How many products and what ProductType mix?
  • Specific IDs / naming convention, or auto-generated (default: ` like H123456`)?
  • Specific Base Unit pool, or pull from existing products of the same ProductType?
  • Specific Product Group, or auto-pick from tenant defaults?

Phase 2 — Discovery (cached per-tenant)

Always do this before the first POST in any session, even if the user supplied all fields explicitly — needed to confirm internal codes.

GET /sap/opu/odata4/sap/api_product/srvd_a2x/sap/product/0002/Product
    ?$top=10
    &$select=Product,ProductType,BaseUnit,ProductGroup,IndustrySector
    &sap-client=

From the result, build per-ProductType pools:

  • BaseUnit pool — e.g. HAWA → [ST, ...], SERV → [LE, ...]. V4 returns internal codes (NOT PC / EA).
  • ProductGroup pool — common values per ProductType.
  • IndustrySector — usually a single value tenant-wide (typically M for demo tenants).

Cache for the session. If empty (fresh tenant), use these conservative defaults: HAWA/FERT/ROH/HALB → BaseUnit ST, ProductGroup A001, IndustrySector M. SERV → BaseUnit LE, ProductGroup A001, IndustrySector M.

Phase 3 — Build payload

Per record:

{
  "Product": "",
  "ProductType": "",
  "BaseUnit": "",
  "ProductGroup": "",
  "IndustrySector": "",
  "_ProductDescription": [
    { "Product": "", "Language": "EN", "ProductDescription": "" }
  ]
}

ID generation: ` (e.g. H for HAWA, F for FERT, S` for SERV) keeps batches scannable.

Phase 4 — CSRF + POST

  1. GET /?sap-client= with X-CSRF-Token: Fetch — capture token + cookies.
  2. POST /Product?sap-client= with the deep-insert payload above. Headers: Authorization, Content-Type: application/json, Accept: application/json, X-CSRF-Token: , Cookie: .
  3. Reuse token across batch; refresh on 403 CSRF token validation failed.

Expected success: HTTP 201 with full product entity in response body (including auto-populated CreationDate, CreatedByUser, BaseISOUnit, etc.).

Phase 5 — Verify

After each POST: extract Product from the 201 response body and append {ok, productID, productType, ts, error?} to create-log.jsonl. After bulk completes, do a spot-check with $expand=_ProductDescription:

GET /Product('')?$expand=_ProductDescription&sap-client=

Confirm IsMarkedForDeletion=false and the description was committed.

Known error catalog

| Code | Cause | Fix | |---|---|---| | CMD_PROD_RAP/003 "Property PRODUCT is a key and cannot be initial" | Deep-insert child missing parent key | Add "Product": "" to each _ProductDescription entry | | MG/142 "Value X not allowed for MARM-MEINH" | Wrong unit code (used V2/ISO PC instead of V4 internal ST) | GET existing product to discover the tenant's actual code | | PMD_MSG/032 "Description of product X not maintained" | Tried to POST Product without _ProductDescription | Description is mandatory at create — include it in deep-insert | | API_PRD_MSG/009 "Create operation not allowed on entity" | Using OData V2 API_PRODUCT_SRV instead of V4 | Switch to V4 path — V2 is read-only for Product header | | M3/098 "Enter a material type" | Missing ProductType | Required field, supply HAWA/FERT/etc. | | (none) "Enter an industry sector" | Missing IndustrySector | Required even though Fiori's manual dialog doesn't ask for it | | HTTP 202 + silent drop (SOAP path) | Used productmdmbulkreplicaterequest SOAP service | Switch to V4 — SOAP needs sender business system registration |

Output structure

/.s4hana-tmp/create-products-/
├── tenant-discovery.json  # per-ProductType pools (BaseUnit, ProductGroup, IndustrySector)
├── payloads.json
├── create-log.jsonl
├── results.json
└── verify-sample.json

Cross-tenant migration notes

  • Source product IDs (MATNR) can be preserved on the target if they're ≤18 chars and the tenant allows external numbering. No internal numbering option exists via API.
  • Unit codes do NOT carry across tenants — translate to the target tenant's internal codes via the Phase 2 discovery.
  • Plant / sales / valuation / procurement views are SEPARATE entities (ProductPlant, ProductSales, etc.) on the same V4 service. The header create handled by this skill is sufficient for basic-data lookup but extending to a plant requires a second POST to ProductPlant.

Reference files

  • references/v4-vs-soap.md — why OData V4 and not the SOAP MDM Replicate service (decision matrix + the silent-drop trap)
  • references/field-reference.md — complete Product entity field list with required vs optional, max lengths, deep-insert nav properties
  • scripts/bulk-product-poster.mjs — reference implementation

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.