REST API

Programmatic access to the AAS Studio extraction pipeline. Send a PDF datasheet, get back a structured Asset Administration Shell extraction result. Useful for integrating AAS file generation into ERP, PLM, or PIM workflows.

Open interactive API explorer, try it out →
TypeScript SDK
@aas-studio/sdk · npm
Python SDK
aas-studio · PyPI
Integration guides
SAP, Siemens, AVEVA, BaSyx + generic
Standards conformance
AAS V3.1, IDTA, IEC 63278 evidence
Generate API key
Settings → API Keys
OpenAPI 3.0 schema
Plug into Postman / openapi-generator

Authentication

Every request needs a Bearer API key in the Authorization header. Generate one in Settings → API Keys. Keys are prefixed sk_aas_ and are shown ONCE at creation. Store them in a secret manager.

Authorization: Bearer sk_aas_a1b2c3d4...

AI EXTRACTION calls count against your monthly quota (Free 20, paid plans 50 or 500 depending on tier, Enterprise unlimited). Validation, repair, templates and the v3 surface do not: only /extractand the embed extraction endpoint consume it. "Each call" here previously said otherwise, which overstated what using the API costs you.

Quickstart: extract from a PDF

Use the official SDK for production work: typed, zero-deps, error classes for every status code. Or stay with curl for quick tests.

TypeScript SDK

import { AasStudioClient } from '@aas-studio/sdk'
import { readFileSync } from 'node:fs'

const aas = new AasStudioClient({ apiKey: process.env.AAS_STUDIO_KEY! })

const { result, provider } = await aas.extract({
  file: readFileSync('./datasheet.pdf'),
  idPrefix: 'urn:acme:aas',
})
console.log(result.assetIdShort, '·', result.submodels.length, 'submodels via', provider)

Python SDK

from aas_studio import AasStudioClient

aas = AasStudioClient(api_key=os.environ["AAS_STUDIO_KEY"])

with open("./datasheet.pdf", "rb") as f:
    response = aas.extract(f.read(), id_prefix="urn:acme:aas")
print(response["result"]["assetIdShort"])

curl (raw HTTP)

curl -X POST https://aas-studio.eu/api/v1/extract \
  -H "Authorization: Bearer $AAS_STUDIO_KEY" \
  -F "file=@datasheet.pdf" \
  -F "idPrefix=urn:acme:aas"

Response (truncated):

{
  "result": {
    "assetIdShort": "UR10e",
    "assetId": "urn:acme:aas:UR10e",
    "assetDescription": "Universal Robots UR10e collaborative robot",
    "submodels": [
      {
        "idShort": "Nameplate",
        "elements": [
          { "idShort": "ManufacturerName", "value": "Universal Robots A/S",
            "semanticIdIrdi": "0173-1#02-AAO677#002",
            "confidence": 95, "tier": "high", "needsReview": false }
        ]
      }
    ]
  },
  "provider": "gemini",
  "warnings": []
}

Endpoints

POST/api/v1/extract
Extract an AAS submodel from a PDF datasheet
Body: multipart/form-data with file (binary PDF, max 20 MB), optional idPrefix, optional apiKey override, optional provider
200Extraction succeeded, returns ExtractionResult
401Missing or invalid Bearer key
402Monthly quota exceeded (returns plan / used / limit)
413File exceeds 20 MB
422PDF could not be parsed (scanned image, malformed)
502LLM provider failed
GET/api/v1/health
Service liveness probe (no auth required)
200Service is up, returns { ok: true, version }

Errors

All non-2xx responses use a stable JSON envelope with an error machine code and a human-readable message. Many errors include an (id=…) correlation tag. Quote it when contacting support.

{
  "error": "extraction_failed",
  "message": "AI extraction failed (id=ab12-3c4d-...). Please retry."
}

Rate limits & quota

Extractions are metered by a monthly quota that the API and the web app share on one counter. Plan caps are Free 20 / Individual 50 / Team 500 / Enterprise unlimited (monthly).

Hitting the cap returns HTTP 402 with your plan, current usage, and limit in the body. See pricing to upgrade.

CI/CD quality gate (validate on every push)

POST /api/v1/validate runs the same three-gate stack the Studio uses — the official AAS XSD, the AASd-* metamodel constraints, and structural checks — so your pipeline can block an export before it reaches a platform. The schema is picked from the AAS 3.x namespace your document declares (3.0 / 3.1 / 3.2; 3.1 when it declares none we recognise), and both version and the validation label name the schema that actually ran — so a 3.0 file reports xsd-3.0+constraints, never a fixed xsd-3.1. Send the AAS environment XML (multipart file or JSON { "xml": "..." }); the response carries valid plus an errors[] list. Fail the job when valid is not true:

# exits non-zero (and fails the CI step) on any validation error
curl -sf https://aas-studio.eu/api/v1/validate \
  -H "Authorization: Bearer $AAS_STUDIO_KEY" \
  -F file=@dist/export.aas.xml | jq -e '.valid == true'

As a GitHub Action step:

- name: Validate AAS export (AAS 3.1 + AASd-*)
  env:
    AAS_STUDIO_KEY: ${{ secrets.AAS_STUDIO_KEY }}
  run: |
    RESPONSE=$(curl -sf https://aas-studio.eu/api/v1/validate \
      -H "Authorization: Bearer $AAS_STUDIO_KEY" \
      -F file=@dist/export.aas.xml)
    echo "$RESPONSE" | jq .
    echo "$RESPONSE" | jq -e '.valid == true' > /dev/null \
      || { echo "::error::AAS validation failed"; exit 1; }

Exit codes: curl -sffails the step on HTTP 4xx/5xx (401 bad key, 413 over the 25 MB cap, 429 rate-limited — 30 validations/min per ACCOUNT, not per key: the limiter is keyed on the user, so two keys on one account share one budget); jq -e fails it when the file is well-formed but not valid. For a one-off manual check without a key, use the free Validate & Repair tool.

Gate on depth, not only valid. The response also reports how deep the check actually went: structural (schema only), semantic (schema + the AASd-* metamodel rules), or full (an official IDTA engine run on top). AAS JSON is validated against the official JSON Schema and then walked by the same AASd-* metamodel gate as XML, so a conformant JSON environment now reaches semantic too — and a JSON document with a real AASd-* violation now returns valid: false, exactly as the same document in XML always did. JSON falls back to structuralwhen the metamodel leg could not run (the JSON Schema rejected the document, or it could not be normalised). If your gate means “XML, fully checked”, assert all three:

echo "$RESPONSE" | jq -e '.valid == true and .depth == "semantic" and .format == "xml"'

OpenAPI schema

Full OpenAPI 3.0 schema lives at /api/v1/openapi.json. Drop it into Postman, Stoplight, openapi-generator-cli, or any AI agent framework that consumes OpenAPI to scaffold a typed client in seconds.

Command palette

Navigate + run actions