Import catalogue devices with an agent
Use an EKX-connected agent to turn one to three manufacturer PDF datasheets or TCC documents into private catalogue records. EKX validates the files, extracts a bounded package, asks for decisions when evidence is ambiguous, shows every curve overlay for approval, and applies the whole package atomically.
You can save verified device facts when a source has no usable curves. You can later import a TCC for one exact private catalogue record without replacing its factual data or current saved curves.
The workflow never changes a project. It creates, reuses, restores, or updates catalogue series, SKUs, compatibility links, and approved TCC curves only after all blocking issues are resolved.
Prerequisites
- Connect your agent as described in Connect an AI agent to EKX, or use
an organization-bound API key with catalog:write.
- The connected user must be an active organization owner or administrator with paid access.
- Add
catalog:readwhen the agent needs to poll the build or retrieve review images. Reading a
build and its review images needs only build ownership, not paid access.
- Reconnect an older OAuth client or create a new API key to grant the catalogue scopes.
- PDF uploads need a shell with network access. Without one, email the PDFs to
[email protected] and EKX makes the import for you.
Find Siemens breaker sources
Use https://sieportal.siemens.com/en-ww/products-services/detail/<part-number> with the exact requested part number. For example, open 3VA6460-0HL41-0AA0. Download the datasheet PDF from the product page, or append ?tree=CatalogTree#specifications to open Specifications, then click the Technical data tab to inspect device facts.
The import requires a local PDF. Use the technical-data tab to verify facts, and check that the downloaded file has a %PDF- signature, a readable page count, and the exact requested part number. Siemens Mall also provides a direct datasheet URL: https://mall.industry.siemens.com/teddatasheet/?format=PDF&caller=Mall&mlfbs=<part-number>&language=en. For a linked characteristics drawing, use the catalogue import skill's Siemens download reference. It documents the public document metadata lookup with ordinary HTTP requests. Discover the actual PdfLink; do not guess a filename from the drawing title. Its model-number search also finds characteristics documents when a general web search or exact SIMARIS link returns no curve. Check applicability, PDF signature, byte count, page count, and drawing identity before upload. If Siemens refuses the request, download the PDF in your browser and give it to the agent. An HTML response is not an importable PDF.
When Siemens states product designation / according to UL file, the import stores that exact value on the part as ulProductDesignation. This differs from the generic product designation, such as "Molded-case circuit breaker". Supply the manufacturer datasheet for that part; do not derive the designation from its part number. Later imports that omit the field preserve a saved designation. Older records need a source-backed correction before the designation appears.
A datasheet's link to a TCC does not supply the graph. When the requested import includes curves, retrieve and upload the original characteristics PDF too. Using it to resolve a fact conflict does not complete the curve import. Keep the confirmed breaker rating visible when discussing a conflicting pickup, for example a 35 A breaker with a disputed 350 A or 400 A instantaneous threshold.
Import a breaker with its electronic trip unit
Include the exact requested breaker and its documented trip unit in one package, and state that scope in the build intent. Keep breaker ratings separate from trip-unit setting choices. Preserve each dial's discrete labels, values, units, and reference basis for the applicable breaker model and rating. These catalogue choices do not select settings for an installed project device, and separate catalogue records do not imply interchangeable hardware.
Treat a TCC PDF as a source of both facts and curves when it contains both. Its settings table can corroborate the manual or datasheet. Deduplicate agreeing facts and resolve discrepancies through the build's issues. Associate the curves with the requested trip unit and documented breaker/rating context; a shared ETU320/330 heading does not require importing both models.
Preserve published tolerances and distinguish minimum tripping from maximum clearing time. A list of available settings does not prove that every setting combination has a plotted curve. Accept a fixed-settings profile only when its complete applicable settings are established and verified against the graph. Do not treat the family plot as one installed curve or fabricate unplotted combinations. Report available setting choices and incomplete curve coverage separately.
For example, ETU320 on a 3VA6460 has independent long-time pickup, long-time delay, and instantaneous pickup dials. Preserve the AA-to-value mapping for each dial and the delay reference at 6Ir when supported by the sources. Choosing AA for pickup does not select AA for the other dials.
Import existing ETAP curves
You can supply native ETAP exports instead of digitizing a PDF. Use the plugin's create_etap_catalog_import tool with the original manifest and point records and reviewed units and trace roles. One build can carry one record for an existing catalogue record, or a whole product line: records of one ETAP manufacturer and base model, which may mix library revisions.
Native builds use the same processing, curve review and revision tools. No PDF upload is needed. Each curve needs only acceptance or rejection. Saved curves are named after the part as the app shows it: its part number, or <record name> · <variant> when it has none, or after the catalogue model and source rating when the build targets no SKU. When the ETAP model carries a library revision, the curve name keeps it, such as LPJ-100SP minimum melt (ETAP 05/02). Choose which revision to import for each rating yourself; EKX imports the records you send. Use the original manufacturer tripping document to check the ETAP export; do not replace native points with a digitized approximation.
Each interpretation must name the export's inspectionFingerprint and its trace IDs. Get both from the inspection route, which checks the unchanged manifest and record without creating a build:
curl "https://joinekx.com/api/v1/catalog-builds/etap/inspect" \
-X POST \
-H "Authorization: Bearer $EKX_API_KEY" \
-H "Content-Type: application/json" \
--data @inspect.jsoninspect.json contains manifestText, recordText, and recordFile, exactly as in the create request. The response returns inspectionFingerprint, the record's model, rating and trip type, each trace's id, section, pointCount and issues, pickup evidence, exported electronic selector IDs, and limitations. It also returns rating: the current in amperes, or the reason the rating cannot import. Vendor-library fuse records add libraryFacts: manufacturer, model, rating label, voltage in kV, speed, rated current and interrupting rating as ETAP stores them. Siemens BLH and QRH2 breaker records add libraryFacts with the frame model and pole counts, and fixedRelease, which says how the record stores its instantaneous trip. To inspect a product line, send records, an array of { "recordFile", "recordText" }, instead of recordText and recordFile. When the records come from several model folders, send manifests as in the create request below and give each record its manifestRef. The response is { "records": [...] }, one result per record; a record that fails inspection reports ok: false with its own error code. Agents use the inspect_etap_catalog_import tool for the same check.
Then create the build with POST /api/v1/catalog-builds/etap and an Idempotency-Key. For one record, the body adds the exact targetCatalogId, an optional skuId, targetApplicabilityEvidence, and one to eight interpretations. A stored-point interpretation looks like this:
{
"inspectionFingerprint": "<from the inspection>",
"currentUnit": { "kind": "amperes" },
"timeUnit": { "kind": "seconds" },
"boundaryMapping": { "kind": "nominal", "traceId": "melting" },
"curveType": "minimum_melt",
"evidenceReferences": ["Reviewed source units and trace role"]
}Use boundaryMapping: { "kind": "band", "lowerTraceId": ..., "upperTraceId": ... } for a tolerance band. Configured thermal-magnetic, magnetic, and electronic records use the thermal_magnetic, magnetic, or electronic interpretation, whose full schema the create_etap_catalog_import tool publishes. The whole request is limited to 2 MiB.
For the supported P10022 BL 100 A and CED6 125 A exports, a manufacturer facts record may lack the fixed-release settings needed to attach its native curve. Send completeMissingFixedSettings: true with one configured thermal-magnetic interpretation, the exact private target, and skuId: null to complete those missing settings in the same reviewed import. EKX adds only missing fixed thermal and magnetic types and the reviewed nominal instantaneous multiple, recording ETAP-derived provenance. That nominal lies inside the native pickup band; it is not a manufacturer-stated factory setting or a selectable dial. Existing conflicting settings refuse the request. Manufacturer facts, ratings, SKUs and compatibility links remain intact. Omit this option for the usual curves-only import.
Vendor-wide library exports (source_type: "etap_vendor_library_point_export") are accepted for fuse records from any manufacturer. Send the model's own manifest.json from points/FUSE/<Manufacturer>/<Model>/, which lists only that model's records, and each record's filename (for example 100A_493583.json) as recordFile. The collection's points/manifest.json also works when it fits in the 2 MiB request. Other record types in these collections return NATIVE_ETAP_UNSUPPORTED_RECORD_TYPE.
The inspection's fuseCurveBasis says what a fuse record's two arrays are, and only the matching interpretation imports:
melting_and_clearing, andetap_average_band(ETAP already applied thetolerancePercentthe
record's notes state to an average curve): map melting to minimum_melt and clearing to total_clear.
average_only: the record stores one average curve. Send it twice with
boundaryMapping: { "kind": "average_current_tolerance", "traceId": "melting", "tolerancePercent": 10 }, once as minimum_melt (every current × 0.90) and once as total_clear (every current × 1.10), at the same times. These curves give an arc flash clearing time; the average curve alone does not.
total_clear_only: the record's note says its one curve is total clearing. Mapclearingto
total_clear only.
unstated_single_curve: one curve with no stated basis. Import one trace as
published_time_current; it gives no clearing time.
ambiguous: the notes and arrays disagree, andreasonsays how. Nothing imports.
Any other interpretation fails with a reason that names the accepted one.
To bring earlier imports of the same records up to these rules, import them again to the same private record: in target mode give each record its existing skuId, or in a product-line build without a target answer POSSIBLE_IDENTITY_MATCH with choose_existing. Each new fuse curve whose SKU already holds curves from the same ETAP record raises CURVE_CONFLICT; replace_existing removes those curves and saves the new ones in the same apply.
Siemens BLH and QRH2 exports (kind: "etap_siemens_blh_qrh2_stored_points") import three-pole records as fixed thermal-magnetic breakers through the thermal_magnetic interpretation, using the two thermal traces and no magnetic traces. ETAP's library is the source for these releases: the instantaneous band it stores sets the curve, and the interpretation's instantaneous pickup is a nominal inside that band, 10 times rating for QRH2 and 11 times rating for BLH. A BLH interpretation also names the current where its clearing floor ends, as domain: { "maxAmps": 22000 } for the 22 kA BLH 100 A. ETAP draws each BLH overload curve on to its instantaneous pickup along its last stored slope; EKX does the same and says so on the curve. Without a target, the build creates a private breaker record named by the family you state in series, such as QRH2, with one part per rating, shown as QRH2 · 200 A.
Allen-Bradley 140G G, H and I fixed breakers are stored in ETAP as two records per rating: a Hot record and a Cold record, which Rockwell prints together as one chart. Send the Cold record with its Hot record from the same manifest as companion: { "recordFile", "recordText" }, both to inspect and to create (inside each record when you send records). The pair has its own inspectionFingerprint; either record alone imports nothing. Map hot_thermal_1 as the lower trace and thermal_2 as the upper, in rated_current_multiple at the exact rating, with the catalogue's fixed instantaneous pickup and a domain. The curve spans Rockwell's whole hot and cold range, so an installed breaker needs no Hot or Cold choice. Inspection also returns allenBradley140gRelease: the frame, the stored pickup band in multiples of rating and the clearing time.
Import a product line
Send records instead of the top-level recordText, recordFile, skuId and interpretations. Each record carries its own recordFile, recordText and interpretations. All records must come from one ETAP manufacturer and one base model, the model without its trailing revision, and a build holds at most 250 records. Different revisions may be mixed, such as LPJ_SP for some ratings and LPJ_SP (05/02) for others; each curve name keeps its own record's revision.
When every record comes from one model folder, send that folder's manifest as manifestText. When revisions are mixed, send manifests instead, at most 8, each with a manifestRef of your choice and the unchanged manifestText, and give every record the manifestRef of the manifest that lists it. Every manifest must be used. The build stores each manifest once.
Two records that would be the same SKU, with the same rating, voltage and speed, fail the request with both record names; send only the revision you chose for that rating. In target mode two records may not name the same skuId.
- With
targetCatalogIdandtargetApplicabilityEvidence, the curves go to that existing record.
Give each record the skuId of its existing SKU, or null for record-level curves.
- Without a target, the build creates a private record and one part per record from the
vendor-library facts. Name the maker's product family as printed in series: { "value": "LPJ-SP", "evidence": "<where the name comes from>" }. ETAP's model or folder name, such as LPJ_SP (05/02) or TM210(3VA41), is a library name, not a family: the request is refused when the series has brackets, an underscore, a current rating, ·, or an ETAP reference. The family becomes the record name and its series. When the maker already has a record in that family with different fixed settings, also send recordName: { "value": "3VA52 TM230", "evidence": "..." }, the family plus the one real qualifier that tells them apart. Each part stores the rated current, the rated voltage (voltage_kv × 1000 V) and the AC interrupting rating at that voltage, and its notes say which ETAP stream the facts came from. Every saved fact is labelled as ETAP library data, not manufacturer datasheet data, except the names, which carry your evidence. A part has no part number unless you show a real one: it is named by its variant, the ETAP rating such as 100 A or 12R, with the voltage added when the line spans several voltages and the speed added when needed to keep parts distinct, and shown as LPJ-SP · 100 A. When a datasheet names the real catalogue number, send it as partNumber: { "value": "LPJ-100SP", "evidence": "<where the number comes from>" }.
{
"series": { "value": "LPJ-SP", "evidence": "Eaton Bussmann LPJ-SP data sheet 1007, title" },
"manifestText": "<points/FUSE/Bussmann/LPJ_SP_(05_02)/manifest.json, unchanged>",
"records": [
{
"recordFile": "100A_493583.json",
"recordText": "<unchanged record text>",
"partNumber": { "value": "LPJ-100SP", "evidence": "LPJ-SP data sheet 1007, ordering table" },
"interpretations": [ "<melting as minimum_melt>", "<clearing as total_clear>" ]
}
]
}With mixed revisions:
{
"series": { "value": "LPJ-SP", "evidence": "Eaton Bussmann LPJ-SP data sheet 1007, title" },
"manifests": [
{ "manifestRef": "LPJ_SP", "manifestText": "<points/FUSE/Bussmann/LPJ_SP/manifest.json>" },
{ "manifestRef": "LPJ_SP (05/02)", "manifestText": "<points/FUSE/Bussmann/LPJ_SP_(05_02)/manifest.json>" }
],
"records": [
{ "manifestRef": "LPJ_SP", "recordFile": "50A_490051.json", "recordText": "...", "interpretations": ["..."] },
{ "manifestRef": "LPJ_SP (05/02)", "recordFile": "125A_493593.json", "recordText": "...", "interpretations": ["..."] }
]
}A build without a target goes through ordinary identity matching. When a similar private series already exists, such as Eaton Bussmann JCW, the build raises POSSIBLE_IDENTITY_MATCH; choose that record or keep the import separate, then resolve any differing facts as usual.
A rating label ending in A, E, C, K or T, or a bare number, imports as that many amperes only when the record states the same rated current. A fraction such as 1/10 A or a mixed number such as 1 1/2 is amperes too. So is a part number whose trailing number, optionally followed by A, E, K or T, equals the stated current, such as DFJ-30 or FWX-35A; that label alone becomes the part number. The original label, such as an E, K or C label, stays in the variant or the part's notes. Paired-fuse labels such as 2-250E or 2x10E, X sizes such as 350X, and curve-letter labels such as 12A_curve_D do not state the rated current and are left out.
An R size such as 9R is not amperes. It imports at the record's stated rated current, so JCG 2R becomes JCG · 2R at 70 A, and its SKU notes and curve limitations say that the continuous rating comes from the ETAP library record. Check that current against the manufacturer datasheet before importing; the inspection response shows the same limitation. An R record that states no positive rated current is left out. These label rules are owner decisions dated 2026-10-07.
Records that cannot import, such as unrecognised labels, damaged traces or a rating that differs from the stated current, are left out with a reason in the build's limitations, and the other records continue. The request fails only when no record can import.
A product line can produce more than 20 curves. Accept them in batches of at most 20 operations per revision; accepting one SKU's curves does not change another's review fingerprint. A native build can save up to 500 new curves.
Import a package
- Calculate the exact byte count and lowercase SHA-256 for each local PDF.
- Set
curveRequirement: "required"when the user requests new manufacturer curves for every
curve-owning record; otherwise use "optional". Set the field explicitly because EKX does not derive it from the intent text. Continue through curve review when curves are in the requested scope.
- Choose
importMode: "package"for a normal import. For a later TCC, use"curves_only", set
curveRequirement: "required", and supply the exact targetCatalogId.
- Upload each file to its returned
uploadUrlwith the returned short-livedUploadcapability. - Start processing with the build's
currentVersion. - Poll the build while it is
processingorapplying. - If it is
blocked, present the complete issue list to the engineer in one question. - For every curve, retrieve both review images and obtain explicit approval before sending
accept_curve.
- Submit the chosen resolutions with the latest
expectedVersion. EKX applies automatically when
no blocking issue remains.
Every JSON mutation requires a unique Idempotency-Key. Reuse that key only for an exact retry of the same method, path, and body. If a network request disconnects, read the build before deciding whether to retry. A completed upload can be replayed only with the exact same bytes.
Create and upload
PDF=breaker-datasheet.pdf
BYTES=$(wc -c < "$PDF" | tr -d ' ')
SHA256=$(sha256sum "$PDF" | cut -d ' ' -f 1)
curl "https://joinekx.com/api/v1/catalog-builds" \
-X POST \
-H "Authorization: Bearer $EKX_API_KEY" \
-H "Idempotency-Key: 7c34d5bb-3c65-44bb-bdd5-a3f6fe3383a5" \
-H "Content-Type: application/json" \
--data "{\"curveRequirement\":\"required\",\"importMode\":\"package\",\"intent\":\"Add the breaker family and its TCC\",\"sources\":[{\"clientRef\":\"breaker\",\"displayName\":\"breaker-datasheet.pdf\",\"contentHint\":\"both\",\"mediaType\":\"application/pdf\",\"bytes\":$BYTES,\"sha256\":\"$SHA256\"}]}"The response contains data.build and data.uploads. Upload the unchanged bytes using the capability from the matching source:
curl "$UPLOAD_URL" \
-X PUT \
-H "Authorization: Upload $UPLOAD_TOKEN" \
-H "Content-Type: application/pdf" \
-H "Content-Length: $BYTES" \
--data-binary "@$PDF"On Windows, run curl.exe; the PowerShell curl alias sends a different request. Send the file unchanged with --data-binary, not -d or a multipart form.
Upload capabilities expire after 15 minutes. If an unfinished upload ticket expires, request a new one with the source's current uploadGeneration; a rotated generation invalidates the old ticket. An exact replay of a completed upload may reuse its generation and declared bytes.
curl "https://joinekx.com/api/v1/catalog-builds/$BUILD_ID/sources/$SOURCE_ID/upload-ticket" \
-X POST \
-H "Authorization: Bearer $EKX_API_KEY" \
-H "Idempotency-Key: 7bd70d78-5593-4348-980e-a2f79bd3cc07" \
-H "Content-Type: application/json" \
--data '{"expectedGeneration":1}'Process and resolve issues
curl "https://joinekx.com/api/v1/catalog-builds/$BUILD_ID/process" \
-X POST \
-H "Authorization: Bearer $EKX_API_KEY" \
-H "Idempotency-Key: d10d72a7-9b8a-41a7-85e9-b70e59b94567" \
-H "Content-Type: application/json" \
--data '{"expectedVersion":0}'Processing returns HTTP 202 Accepted while extraction continues. Poll the build with GET. When allowedActions includes resume_processing, submit process again with the current version and a new idempotency key. A pending curveOutcome: "processing" means curve extraction has not settled.
Blocked responses contain stable issue keys, allowed response types, and evidence locators. Submit only allowed operations and the latest version:
curl "https://joinekx.com/api/v1/catalog-builds/$BUILD_ID" \
-X PATCH \
-H "Authorization: Bearer $EKX_API_KEY" \
-H "Idempotency-Key: 4321ce59-995f-4b79-9981-00b7ee5d885d" \
-H "Content-Type: application/json" \
--data '{"expectedVersion":1,"operations":[{"type":"provide_value","issueKey":"catalog-issue:v1:...","value":600}]}'Use provide_value with null to omit an optional fact after review. Add a short reason when the source statements disagree, for example: "Description implies 350 A; page 2 states 400 A. Leave unset pending manufacturer confirmation." EKX keeps the reason and reviewed source evidence in the saved record's limitations. Required facts, including a new breaker's trip mode, cannot be omitted.
When an issue path ends in .identity, its evidence includes the required provide_value shape. Send all three fields as one object:
{
"type": "provide_value",
"issueKey": "catalog-issue:v1:...",
"value": {
"manufacturer": "Mersen",
"modelNumber": "A200C",
"category": "fuse"
}
}Supported identity categories are breaker_lv, electronic_trip_unit, thermal_magnetic_trip_unit, and fuse. A source for another catalogue device, such as a protective relay, medium-voltage breaker, or overload relay, raises UNSUPPORTED_CATEGORY with no allowed response, because import does not support that device yet.
Match existing records
- A correction build binds only the item whose category matches the
targetCatalogIdrecord. An
electronic breaker's linked trip unit is matched to the catalogue like any other item.
- Two package items that resolve to one catalogue record raise
MULTIPLE_PRODUCTS. Send
choose_candidate with the localRef of the item to save; the others are omitted.
- EKX saves each manufacturer under one brand name. Legal-entity names and other spellings, such as
Siemens Industry, Inc. or SIEMENS, become Siemens, so they never conflict. An unlisted manufacturer takes the spelling the catalogue already uses. Sub-brands such as Square D, Cutler-Hammer and Westinghouse keep their own names.
- A new or renamed record, a changed series, and a new part must follow the naming rules. A series
is the maker's product family as printed, such as 3VA41, with no brackets, underscore, current rating, · or ETAP reference; a record name may add one qualifier, such as TEY 30 A, when its series is stated. A part number is a real orderable number: one that is the series plus a description, such as TM210(3VA41) 30 A, is not. A name that breaks a rule raises INVALID_CATALOG_NAME with what to change. Send provide_value with a corrected name; for a made-up part number, null keeps the part with no part number, named by its variant. Names the catalogue already holds are not re-checked.
- A part number that already belongs to another series from the same manufacturer raises
POSSIBLE_IDENTITY_MATCH. Send choose_existing to update that series, or create_separate.
- An archived part raises
INACTIVE_MATCH_REQUIRES_RESTORE. Sendrestorewith the part ID from the
issue evidence to bring it back; EKX never reactivates an archived part without that decision.
- When every item already exists as an EKX standard record, the build fails with a message that
the device is already in the EKX catalogue. Nothing is saved.
Builds that cannot continue
A blocking issue that offers no response, with no other issue that does, ends the build. EKX finishes it as failed, and safeFailure carries the issue's message. Examples are unsupported devices, pages without product facts, terminal provider failures, and too many pages for curves. Cancel an unfinished build to release its active slot.
Do not submit curve points. Retrieve the source and overlay routes listed in the catalogue-build reference, compare both images, then return the review fingerprint with accept_curve or send reject_curve.
When required curves are missing or curve extraction cannot finish, EKX keeps the verified factual package and returns a recoverable curve issue. If the engineer chooses continue_without_curves, submit that offered resolution once with the other current decisions. The waiver omits every new curve from this build, including already accepted candidates, and preserves curves already saved on the target catalogue records. A temporary failure remains retryable while the issue offers retry_processing.
Review current and time tolerances
Supply the datasheet and curve document together when tolerance notes appear on different pages. Each current curve review exposes toleranceSummary with separate current/time rules, units, reference values, applicability, and source/page evidence. toleranceCoverage reports the count of fully examined pages and the omitted or unreadable page ranges. Public summaries omit raw storage keys, source hashes, and point arrays.
Incomplete coverage blocks acceptance even when the missing page belongs to a graph-free datasheet. Create a new build with a smaller complete packet using the reported page ranges. Retrying the same packet does not increase the page budget. A verified not_stated result permits nominal operation but supplies no conservative trip time; it does not mean zero tolerance.
When a tolerance issue offers correct_curve_metadata, select an existing source-backed candidate:
{
"type": "correct_curve_metadata",
"issueKey": "catalog-issue:v1:...",
"curveRef": "curve-reference-from-review",
"metadata": {},
"tolerance": {
"sourceRuleIds": ["tolerance-statement:v1:..."],
"selectedCandidateId": "tolerance-statement:v1:..."
}
}Use only IDs returned for that build. Optional scope, relation, lower, and upper must agree with the retained source evidence; they cannot create an unsupported numerical rule. A correction regenerates the affected overlay and invalidates earlier acceptance. Retrieve and review the new source/overlay pair before accepting its new fingerprint. Reject an unsupported curve or use the offered whole-build facts-only waiver; accepting its nominal trace cannot clear a tolerance blocker.
Completed summaries retain the accepted tolerance meaning after temporary draft cleanup. Numerical or applicability corrections can make an installed profile and its study results stale.
Preserve qualified voltage ratings
An interrupting rating can include a slash or wye voltage qualification. Keep both voltages with the rating. For example, 18 kA at 600Y/347 V is represented as:
{
"voltage": 600,
"kA": 18,
"qualification": { "kind": "wye", "lineToGroundVoltage": 347 }
}Use kind: "slash" when the source uses slash notation without a wye designation. A plain rating remains { "voltage": 480, "kA": 35 }. Follow the manufacturer source; do not infer a qualification or remove one to make the rating fit.
A facts-only update preserves the catalogue's existing curve outcome. Its build summary still reports that no new curves were provided; it does not count previously saved curves as new imports.
If extraction loses a visible qualification, the import asks for a corrected structured rating. The catalogue and editor retain the qualification. Automatic interrupting-capacity checks do not treat qualified ratings as unrestricted ratings when the required supply conditions are unverified. An independently documented plain-voltage rating remains available.
Add a TCC later
Create a new build with importMode: "curves_only", curveRequirement: "required", and the exact private catalogue record ID as targetCatalogId. EKX accepts only reviewed curve evidence that it can associate with that record and its existing SKU, when applicable. It ignores extra products in a multi-product PDF and preserves the target's identity, configuration, description, standard, SKUs, compatibility, factual provenance and limitations, and saved curves unless review expressly authorizes a curve replacement.
Read curve results
An applied summary reports curveOutcome and record-specific limitations for each record. The outcome describes this import:
| Outcome | Meaning |
|---|---|
not_expected | This record does not own an imported curve. |
not_provided | The source provided no new curve, including a missing-curve waiver. |
imported | EKX saved the accepted new curve evidence. |
incomplete | EKX saved only part of the supported curve coverage. |
skipped_after_failure | Curve extraction failed and the engineer continued without new curves. |
not_imported | The source supplied a curve, but the engineer deliberately omitted it. |
These outcomes explain the import. Current catalogue evidence remains the authority for whether a device has usable time-current data.
Limits and retention
- 1–3 PDFs, 90 MiB per file, 270 MiB total, and 500 pages per PDF.
- One extraction examines at most 24 pages across all PDFs, and curves need every supplied page
examined. When curves are required, a source's contentHint is curves or both, or EKX finds a time-current curve page in the PDFs, a source set over 24 pages fails before extraction and is not charged. Upload only the pages with the curves and settings.
- Up to 5 catalogue items, 100 SKUs per item, 20 compatibility links, and 20 newly saved curves per
build. A native ETAP build takes up to 250 records and saves up to 500 new curves. You can review more candidates and reject those you do not want to save.
- Active builds expire 30 days after their last successful activity.
- Raw fact PDFs are queued for deletion after apply, cancel, failure, or expiry. Shared
content-addressed objects are not deleted while another row references them.
- Curve source pages and overlays remain reviewable for the active build, then enter exact-key
cleanup when the build becomes terminal.
- Thirty days after a terminal result, EKX removes extracted facts, resolutions, locators, and
review artifacts. It retains a safe status tombstone and the applied record summary.
- Organization deletion removes catalogue-build database rows and both organization storage
prefixes.
See Catalogue-build API reference for the complete route and status contract.