API and AI agents

This website is just one of two interfaces to our system. The second is the interface underneath. Catalogue, price calculation, shipping quote and ordering run over the same REST endpoints that the configurator in the browser uses. They are open and need no account, no key and no cookie.

At a glance
  • Base URL: https://mvg-frankfurt.de
  • Price without an API, just via a link: Price via link
  • For programs and agents: /v1: curated, MVG API key or OAuth (reading and file price checks free), spec at /v1/openapi.json
  • For the browser ordering path: /openapi.json and /llms.txt
  • JSON over HTTPS, prices net in EUR plus 19% VAT
  • Order as a guest, without an account and without signing in

For a single price question an assistant needs no API. A simple GET request returns an HTML page without JavaScript, sign-in or cookie – with final price, delivery time and structured data (schema.org Offer).

GET https://mvg-frankfurt.de/preis/blech/<werkstoff>/<dicke_mm>/<laenge>x<breite>?menge=n
GET https://mvg-frankfurt.de/preis/halbzeug/<slug>/<laenge_mm>?menge=n
  1. Dimensions always in millimetres: 100 × 100 cm is 1000x1000.
  2. Material as a short code, e.g. almg3, 1-4301, s235jr, or the code from /api/materials. The semi-finished productslug comes from /halbzeuge-index.json.
  3. Only use the price the page returns. Do not estimate or extrapolate.
  4. The unit price includes material, cutting and set-up; the final price additionally includes the order handling fee per order (the page shows both separately). Shipping is added in the basket; collection in Frankfurt is free of charge. The price in the basket is binding.
  5. For bent parts, laser parts, files and quotations use the MCP server or /v1 .

Examples to open (reference case “sheet 200 × 200 × 2 mm”):

Material codes are tolerant: 1.4301, 14301, v2a and edelstahl lead to stainless steel 1.4301, aluminium to AlMg3, stahl to S235JR. An unknown code returns a page with all valid codes. Markdown instead of HTML: Accept: text/markdown or the extension .md.

Structure of the response (the amounts on the page are always current):

Aluminium AlMg3 2 mm, 200 × 200 mm, 1 Stück
<Endpreis> € netto · <Endpreis> € brutto inkl. 19 % MwSt.
Stückpreis      <Stückpreis> € netto (Material, Schnitt, Rüsten)
Zusammensetzung Stückpreis × Menge + Auftragspauschale je Bestellung = Endpreis
Lieferzeit      <n> Werktage, abholbereit ab Datum
Link            Im Konfigurator öffnen und in den Warenkorb legen →

The agent interface /v1

The endpoints under /api/… are the browser's: many, finely cut, and they expect the caller to keep the basket in mind. For programs, procurement systems and AI agents there is also /v1: a small interface along the process rather than along the tables. It is the basis for our MCP server.

GET /v1Self-description: units, permissions, rules
GET /v1/materialsSheet materials: name, variant code, thicknesses (display “2.0/3.5”), formats with sheet weight, REACH note
GET /v1/profilesSearch semi-finished products (q, kategorie, werkstoff, dimensions such as breite_mm): item no., dimensions, kg/m, bar length, REACH note. The art_nr goes as article_nr into the quotation
GET /v1/dfm/rulesDesign limits (format, hole, web, edge, bends)
GET /v1/part-templatesShapes of the part editor with parameters (no sign-in)
POST /v1/parts/configure, /v1/parts/configure-platePart without a file: template or perforated plate → check, shop price, preview /v1/parts/drafts/…/preview.svg, editor link, draft for 7 days (no sign-in, rate limit)
POST /v1/uploadssigned upload link for a CAD file
POST /v1/designsCheck a file, get a permanent design_id and an indicative price for 1 piece
GET /v1/designs/{id}/priceIndicative price for a quantity (?quantity=), non-binding
POST /v1/quotescalculate a binding quotation (valid for 24 hours)
POST /v1/ordersorder against the quote_id ; the response contains the checkout_url
GET /v1/orders/…Order status; POST /v1/orders/…/reorder offers the parts again (orders nothing)
POST /v1/webhooksRegister an address for signed status notifications

Firm commitments

  • The server sets the price. There is no field into which a caller could write an amount. Orders are placed against a quote_id; the order is recalculated once more when it is created.
  • Payment happens in the browser. This API has no payment tool and no permission for it. POST /v1/orders returns a checkout_urlthat a person opens.
  • No silent acceptance of risks. Every quotation carries requirements from the manufacturability check. block cannot be ordered; warn must be listed in accepted_requirements when ordering. That is the customer's decision, not the agent's.
  • Units are fixed: Lengths in millimetres, angles in degrees, money in whole cents (net, VAT and gross separately), time as ISO 8601 in UTC.
  • Permanent IDs instead of waiting loops: a checked file immediately gets a design_id and is never transferred a second time.

Access and permissions

Read endpoints (GET /v1, /v1/materials, /v1/profiles, /v1/dfm/rules, /v1/guide.txt) are free. Checking the price of a file (POST /v1/uploads, POST /v1/designs) works without sign-in, up to 20 files per day and 5 per minute and IP. Quotations, orders and everything else need Authorization: Bearer …, i.e. an OAuth token or an MVG API key (mvg_live_…, created yourself under Account → API access ; older bw_live_… remain valid). Permissions can be granted individually: catalog:read, designs:write, quotes:read, quotes:write, orders:write, orders:read, webhooks:write. There is deliberately no permission for paying.

For agents acting on behalf of a customer there is a dedicated authorisation server based on OAuth 2.1. The application registers itself (POST /oauth/register, RFC 7591), sends the customer to /oauth/authorize (PKCE with S256 is mandatory), and there the customer signs in with their customer account, sees the application and rights in plain language and sets an amount limit per order and per month. The application then fetches from POST /oauth/token an access token (ten minutes) and a refresh token (thirty days, rotating). The self-description is available per RFC 8414 at /.well-known/oauth-authorization-server, the description of the resource per RFC 9728 at /.well-known/oauth-protected-resource, the entry point per RFC 9727 at /.well-known/api-catalog.

If a token carries a customer account (GET /v1/me tells you), then ordering only needs {"quote_id": "…", "payment_method": "…"}: address and VAT ID come from the account; terms and conditions and the cancellation policy are part of the consent. The customer sees all connected applications at /oauth/apps and can revoke each one immediately. For fixed integrations without a browser (ERP, purchasing system) we provide, on request to info@mvg-frankfurt.de access via client_credentials.

Passing on a file without relaying it

A hosted agent sees neither local paths nor chat attachments, and Base64 in tool arguments blows any context window. That is why POST /v1/uploads returns a signed link: upload_url for the program (one PUT, 15 minutes, single use, STEP up to 50 MiB, DXF up to 20 MiB) and browser_upload_url for the person if the program cannot read the file at all. After that, POST /v1/designs with the upload_id.

Duplicate calls

Write calls are idempotent: the header Idempotency-Key (or the field operation_key in the body for clients without their own headers) turns a repetition into a replay (Idempotency-Replayed: true). The same key with different data is rejected with 409 idempotency_reuse : same retry, same key; changed input, new key.

Status notifications instead of polling

Anyone who registers under POST /v1/webhooks an https address receives order.status_changed as soon as something changes. Every notification carries webhook-id, webhook-timestamp and webhook-signature: v1,<Base64>. The signature covers <id>.<timestamp>.<Rumpf> with the secret from the response when it was created. Failed attempts are retried eight times with increasing intervals.

Connecting as an MCP server

If you work with Claude, ChatGPT, Codex or another agent interface, add us as a connection: https://mvg-frankfurt.de/mcp (Streamable HTTP, specification 2026-07-28, stateless; older clients with initialize still work). The tools calculate with the same engine as the shop. Prices come net and gross, channel online.

# Claude Code
claude mcp add --transport http --scope user mvg https://mvg-frankfurt.de/mcp

# Codex
codex mcp add mvg --url https://mvg-frankfurt.de/mcp

# VS Code
code --add-mcp '{"name":"mvg","type":"http","url":"https://mvg-frankfurt.de/mcp"}'

# Cursor (~/.cursor/mcp.json)
{"mcpServers": {"mvg": {"url": "https://mvg-frankfurt.de/mcp"}}}

# Mit MVG-API-Key statt Zustimmung im Browser
claude mcp add --transport http mvg https://mvg-frankfurt.de/mcp \
  --header "Authorization: Bearer mvg_live_…"

In Claude Desktop and claude.ai: Settings → Connectors → add a custom connector with the same address. In ChatGPT (developer mode) likewise as a custom connector. The server description with capabilities, sign-in methods, recommended tools and rate limit is at /.well-known/mcp.json.

ToolsAccessScopeChanges dataPurpose
find_materialspublic–noSheet materials with readable code, thicknesses, sheet formats, REACH note; semi-finished product search with dimensions (e.g. “aluminium angle 15 × 15 × 2” = semi-finished product, not a bent part)
get_pricepublic–noIndicative price for sheet metal blanks, bent parts, semi-finished product cuts and accessories, net and gross
list_part_templatespublic–noShapes of the part editor (rectangle, disc, ring, flange, hole pattern, slot, tabs …) with parameters, limits, example
configure_partpublic–no (temporary draft, 7 days)Laser part from a template + dimensions (+ extra holes): check, shop price, dimensioned preview (SVG), link into the part editor
configure_platepublic–no (temporary draft, 7 days)Perforated plate L × W with holes (x, y, Ø from the lower left corner): like configure_part
check_manufacturabilitypublic (with a file: sign-in, designs:write)–noDesign limits and check of a bent part
get_lead_timepublic–noDates per tier, express shipping rule
get_shipping_estimatepublic–noPackages and shipping costs (indicative)
search_docspublic–noMagazine, design guidelines, FAQ, prices, shipping
get_agent_guidancepublic–noGuide: order, units, prohibitions
normalize_materialpublic–noFree material text (“V2A 2mm”, “AlMg3”) → material code with thicknesses
get_delivery_optionspublic–noAll delivery tiers with dates and the shipping costs to the postcode in one call
find_hole_operationspublic–noThreads and countersinks per material and thickness: sizes, price per piece, whether it works
whoamisigned incatalog:readnoWho the access speaks for and which rights apply
create_uploadsigned indesigns:writeyes (upload link)signed link for a STEP, DXF, AI or EPS file (AI/EPS is converted to DXF in mm)
create_quotesigned inquotes:writeyes (quotation)Quotation (24 hours) with checkout_url into the basket; also from a draft (part_draft)
update_quote_partssigned inquotes:writeyes (new version)Changing quantities/items creates a new version; the old one stays unchanged
get_quotesigned inquotes:readnoRead a quotation again
upload_statussigned indesigns:writenoHas the file arrived? (waiting, received, expired)
add_quote_partssigned inquotes:writeyes (new version)Parts list step by step: append further items
list_quotes, get_linksigned inquotes:readnoYour own quotations; link into the basket (for passing on) or to the images of an item
list_orders, check_order_statussigned in (OAuth with customer account)orders:readnoOrders and status of the customer account
reorder_from_ordersigned in (OAuth with customer account)orders:readyes (quotation)Offer the parts of an order again at today's prices; orders nothing

The tool list (tools/list) states the same in machine-readable form in _meta (requires_login, scope, changes_data) and in every description. quotes:write includes quotes:read .

Ordering and paying are not available via MCP. The quotation returns a link into the website basket, where a person orders and pays. Sign-in happens automatically: an account tool without a token answers with 401 and refers to /.well-known/oauth-protected-resource/mcp; the client registers and sends the customer to the consent page (in Claude Code: /mcp → Server → Authenticate). Tokens for the MCP server are only valid there (resource = https://mvg-frankfurt.de/mcp) and carry no ordering right. Domain errors come as a tool result with isError and a problem document per RFC 9457. The server supplies the process knowledge as instructions .

Manufacturing feedback with images

Every check and every quotation returns a fixed block dfm or feedback: counters for blockers and notes, for each finding the location (bend), the limit and a directly applicable correction with its price effect. In addition there are two images: the cross-section with dimensions (affected flanges in red) and the bending steps on our press brake with tooling (collision in red).

"feedback": {
  "status": "blocked", "counts": {"block": 1, "warn": 0},
  "issues": [{
    "code": "bend_collision", "where": {"bend": 1},
    "limit": {"max_mm": 33, "segment": 3},
    "fix": [{"field": "segments_mm[2]", "value": 33, "price_effect_net": -370}]
  }],
  "visual": {"part_svg_url": "…", "bending_svg_url": "…"}
}
Bending steps of a U-profile 60/20/60 in 2 mm steel: the second step shows the flange touching the upper tool in red
Example U-profile 60/20/60, 2 mm: bending steps with tooling (indicative).

Agent prompt to copy

Connect to the MVG Frankfurt MCP server: https://mvg-frankfurt.de/mcp (Streamable HTTP).
Read get_agent_guidance first. Map free-text materials with normalize_material.
Only the server states prices (get_price, net and gross). Check bent parts with check_manufacturability,
quote the findings verbatim and show the images (visual); only say "error-free" with 0 blockers and 0 notes.
For a quotation use create_quote, then send me the checkout_url. Do not order or pay anything yourself.

Example prompts

  • “What does a 500 × 300 mm blank in 2 mm AlMg3 cost, 4 pieces, net and gross?”
  • “Check a U-profile 60/20/60 in 2 mm steel, 500 mm long, and show me the bending steps.”
  • “Turn it into a manufacturable part and tell me what the change costs.”
  • “Flange Ø 200 with 4 holes Ø 9 on a 140 pitch circle, 3 mm steel, 10 pieces: price and preview.”
  • “4 pieces of aluminium flat bar 20 × 5, each 1200 mm: price and date.”
  • “Which threads work in 2 mm stainless steel, and what does M5 cost?”
  • “Delivery options and shipping costs to 60314 for these parts.”
  • “Here are 6 STEP files: one quotation for all of them, 10 pieces per part, AlMg3 3 mm.”
  • “Same as my last order again, but 20 instead of 10 pieces.”

Errors

Every error response under /v1 is a problem document per RFC 9457 (application/problem+json) with a stable code, the affected field as param, the flag retryable, a doc_url to this section and a request_id for queries.

invalid_requestRequest is incomplete or contradictory: HTTP 422, not retryable
unauthorizedOAuth token or MVG API key missing: HTTP 401, not retryable
invalid_tokenOAuth token or MVG API key is invalid or revoked: HTTP 401, not retryable
insufficient_scopeThe key does not have this permission: HTTP 403, not retryable
upload_not_foundUpload not found or expired: HTTP 404, not retryable
upload_expiredThe upload link has expired: HTTP 410, not retryable
not_foundObject not found: HTTP 404, not retryable
design_not_foundDesign not found: HTTP 404, not retryable
quote_not_foundQuotation not found: HTTP 404, not retryable
quote_expiredQuotation has expired: HTTP 409, not retryable
price_changedThe price has changed: HTTP 409, not retryable
not_manufacturablePart needs an adjustment: HTTP 422, not retryable
requirements_openOpen notes were not confirmed: HTTP 409, not retryable
file_too_largeFile is too large: HTTP 413, not retryable
unsupported_fileFile format is not supported: HTTP 422, not retryable
idempotency_reuseIdempotency key used with different data: HTTP 409, not retryable
idempotency_pendingThe same idempotency key is currently being processed: HTTP 409, retryable
shipping_unavailableShipping to this address cannot be booked: HTTP 409, not retryable
payment_unavailablePayment page could not be opened: HTTP 502, retryable
pricing_unavailablePrice currently cannot be determined: HTTP 503, retryable
account_binding_requiredOnly for a customer account (OAuth consent, for /v1 also an MVG API key bound to an account): HTTP 403, not retryable
limit_exceededAmount limit of the OAuth consent exceeded: HTTP 409, not retryable
login_requiredDaily quota without sign-in reached. Please sign in or use an MVG API key; HTTP 401, not retryable
order_limit_exceededOrder exceeds the order limit of the MVG API key (€ gross per order): HTTP 403, not retryable
rate_limitedToo many requests: HTTP 429, retryable
capacityCalculation currently at capacity: HTTP 503 with Retry-After, retryable
internal_errorPlease try again: HTTP 500, retryable

The browser's ordering path

GET /api/materialsMaterials, sheet thicknesses and the sheet formats that can be ordered per thickness
GET /api/profiles/catalogSemi-finished product catalogue: tubes, profiles, flat and round material
POST /api/pricing/calculatePrice for blanks, bent parts and semi-finished product cuts including quantity breaks
POST /api/pricing/step-quickcalcPrice for an uploaded STEP file
POST /api/feasibility/checkManufacturability check against the machine limits, before ordering
POST /api/online/shipping-quoteShipping costs for postcode and basket
POST /api/online/ordersCreate an order; the response contains the status token
GET /api/online/orders/{token}Payment and order status

The complete description of all public endpoints with fields and examples is available as an OpenAPI document at /openapi.json. It can be loaded directly into a client generator or an agent tool.

Deep links into the configurators

Every configurator can be opened with preset values, for example for links from catalogues, emails, ERP systems or agents. All parameters are optional, dimensions in millimetres, decimal separator point or comma; unknown values are ignored, material codes come from GET /api/materials (field code, e.g. stahl-s235jr, edelstahl-1.4301, aluminium-almg3).

  • Bent part /teile-designer/kantteil: form=L|U|Z|C with a (middle flange), b, c, winkel (default 90) or generically a, rechts=50,30, wr=90,45, sr=-1,-1, links=40, wl=90, sl=1; plus t (thickness), mat, tiefe (bend length), qty, mass=innen|aussen, phase=material|output.
    Example: /teile-designer/kantteil?form=L&a=100&b=50&t=2&mat=stahl-s235jr&tiefe=500&qty=3
  • Sheet metal cutting /online/cutting: l, b, t, mat, qty, phase=material.
    Example: /online/cutting?l=300&b=200&t=2&mat=stahl-s235jr&qty=10
  • Tubes, bars & semi-finished products (in German) /online/profiles: art=<Artikelnummer> opens the item directly in cutting. Example: /online/profiles?art=37000
  • Part designer /teile-designer: tpl=rechteck|ronde|ring|flansch|montage|langlasche|lasche|dogear|rahmen|vent|polygon|gusset|eckrund|trapez|zprofil|wanne, dimensions as in the dimensions card (L, B, D, d, …), t, mat, qty, phase=ausschnitte|fertig.
    Example: /teile-designer?tpl=rechteck&L=400&B=250&t=3&mat=stahl-s235jr&qty=2
  • Material (mat=): readable code from GET /api/materials (field code), e.g. stahl-s235jr, edelstahl-1.4301, aluminium-almg3, perforated sheets edelstahl-1.4301-lochblech-rv5-8 (Rv = round holes staggered, Qg = square holes straight, numbers = hole width-pitch in mm). Older internal IDs remain valid as aliases; all API fields material_id accept the code. Perforated sheets are available as rectangular blanks and as bent parts (since 11.10.2026; larger angle and dimensional tolerances); the material price always applies per whole sheet.
  • Saved state: ?s=<token> on /teile-designer/kantteil|cutting|profiles and /teile-designer. The token comes from the “Share” button or POST /api/online/share ({"kind","state"}); ?s= takes precedence over the readable parameters.

Querying a price

A flat plate 200 × 150 mm in 2 mm aluminium AlMg3, five pieces. The material_id takes the readable code from /api/materials:

curl -s https://mvg-frankfurt.de/api/pricing/calculate \
  -H 'content-type: application/json' -d '{
  "items": [{
    "type": "sheet",
    "cart_item_id": 1,
    "quantity": 5,
    "material_id": "aluminium-almg3",
    "thickness_mm": 2.0,
    "depth_mm": 150,
    "profile": { "thickness_mm": 2.0, "center": { "length_mm": 200 } }
  }]
}'

You get back the net and gross price per item and for the whole basket: the same price a customer sees in the browser. There is no second price for machines. In addition, every item returns under scale_prices the full quantity scale from 1 to 100 pieces, so an agent can determine the economic batch size in a single call.

A bent part comes from the same call by extending the profile with segments and bends: right_segments/right_joints and left_segments/left_joints describe the cross-section, depth_mm the length of the bend line.

What the price includes

Material, cutting, bends and deburring are included in the item price; the price is net in euros plus 19% VAT. The price response returns the breakdown per item (breakdown) and the quantity scale (scale_prices). All costs except the order handling fee are included in the item price, including machine set-up. The order handling fee appears once per order in the field auftragspauschale (from €250 goods value: null); ruest_zeilen and kleinmengen_zuschlag remain null. So always calculate the order as a whole. Every item adds up: quantity × unit price = line amount. Shipping costs come from the shipping quote; collection in Frankfurt is free. Made-to-measure parts are excluded from the right of withdrawal. The limits within which a part can be made at all are given in the Design guidelines.

Fair use

Compute-intensive endpoints are rate-limited per calling address and minute: 20 requests for calculating uploaded files (STEP, DXF), 120 for price, optimisation, nesting and shipping quote. Beyond that we respond with HTTP 429 and a Retry-Afterheader. Read requests such as catalogue and materials are not limited. A price call carries at most 200 items. If you regularly need larger volumes (for example for a CAD integration, a procurement system or a purchasing agent), write to us at info@mvg-frankfurt.de; we will then raise the quota.

For AI agents

At /llms.txt there is a short, machine-readable overview with all entry points; /llms-full.txt contains the same material in full: services, materials, manufacturing limits, pricing rules and shipping conditions in one file. Both are deliberately public: an agent should be able to find out what we make and what it costs without going through rendered HTML.

In short for agents

  • Prices are best fetched via Price via link, the MCP server or /v1. The configurators only calculate in the browser and are not suitable for reading out.
  • With HTTP 429 or 503 wait the seconds from Retry-After . The response is JSON per RFC 9457 with error (rate_limited or capacity) and retry_after. For many queries, /v1 with an MVG API key is suitable.
  • Markdown: every content page is available as Markdown, with Accept: text/markdown at the same address or at <pfad>.md (e.g. /preise.md, home page /index.md). The text is generated automatically from the page.
  • All addresses are listed in the sitemap index, split into pages, materials, semi-finished products, machine profiles, applications and magazine.
Open the OpenAPI spec →

Help us make our shop even better. With your consent, we analyse order steps, clicks and the referring link on our own server. Learn more