Developer API · Version 1

RailKernel locomotive API

A read-only, server-to-server API for retrieving one complete locomotive record or all locomotive variants for a manufacturer/article combination from the RailKernel Model Database (RMDB), including product identity, prototype data, technical properties, decoder functions, media metadata and external links.

1. API contract

Base URL
https://railkernel.nl/api/v1
Resource
GET /locomotives.php
Current version
v1
Format
JSON encoded as UTF-8
Access
HTTPS with a Bearer API key
Required scope
rmdb:locomotive:read
Caching
Responses currently use Cache-Control: no-store

The endpoint retrieves either one exact locomotive variant or the collection belonging to one manufacturer and catalogue number. It does not provide bulk export, unrestricted search or mutation operations. An HTTP GET is the only supported method.

2. Authentication

Send the issued API key in the HTTP Authorization header. Never put an API key in a URL or query parameter.

Authorization: Bearer rk_live_<your-api-key>

Keys are shown only when issued, are assigned to one integration partner and can be revoked or replaced independently. Do not embed a key in browser JavaScript, a mobile application, a public repository or downloadable software. Calls must originate from a controlled server.

3. Requesting a locomotive

Preferred: stable RMDB identifier

Use the locomotive’s stable rmdb_uid as id. The colon and any other reserved characters must be URL-encoded by the HTTP client.

curl --fail-with-body \
  --request GET \
  --header "Authorization: Bearer ${RAILKERNEL_API_KEY}" \
  "https://railkernel.nl/api/v1/locomotives.php?id=piko%3A40375"

Collection: manufacturer and catalogue number

Supply exactly vendor and catalog_number to retrieve every locomotive variant recorded for that article. Both parameters are mandatory: a vendor or catalogue number on its own is rejected. The response remains a collection when only one locomotive is found.

curl --fail-with-body \
  --get \
  --header "Authorization: Bearer ${RAILKERNEL_API_KEY}" \
  --data-urlencode "vendor=piko" \
  --data-urlencode "catalog_number=40375" \
  "https://railkernel.nl/api/v1/locomotives.php"

Alternative: complete composite key

If no RMDB identifier is available, supply all four key components. catalog_suffix is required even when its value is empty, and variant_no starts at 1.

curl --fail-with-body \
  --get \
  --header "Authorization: Bearer ${RAILKERNEL_API_KEY}" \
  --data-urlencode "vendor=piko" \
  --data-urlencode "catalog_number=40375" \
  --data-urlencode "catalog_suffix=" \
  --data-urlencode "variant_no=1" \
  "https://railkernel.nl/api/v1/locomotives.php"
ParameterRequiredMeaning
id or rmdb_uidPreferredThe stable RMDB locomotive identifier.
vendorArticle collection or composite requestTechnical manufacturer name, compared case-insensitively. Must be supplied together with catalog_number.
catalog_numberArticle collection or composite requestExact catalogue number; do not convert it to a number. Must be supplied together with vendor.
catalog_suffixExact composite request onlyExact suffix, or an explicitly supplied empty value. Must be supplied together with variant_no.
variant_noExact composite request onlyInteger from 1 through 65535. Must be supplied together with catalog_suffix.

4. Response envelope

A successful request returns HTTP 200. The locomotive resource is always found at data.locomotive.

{
  "success": true,
  "data": {
    "locomotive": {
      "identity": {
        "id": "piko:40375",
        "vendor": "piko",
        "catalogNumber": "40375",
        "catalogSuffix": "",
        "variantNumber": 1
      },
      "product": { "name": "…" },
      "vendor": { "displayName": "Piko", "aliases": [] },
      "railway": { "company": "NS", "country": "NL" },
      "scale": { "gauge": "N", "ratio": "1:160" },
      "dimensions": { "lengthMm": 104 },
      "electrical": { "powerSystem": "DC", "digitalProtocol": "DCC" },
      "features": {},
      "technical": {},
      "decoders": [],
      "media": { "images": [], "manuals": [] },
      "links": { "manufacturerProductUrl": null, "retailers": [] },
      "pricing": { "msrp": null, "currency": null },
      "remarks": null,
      "provenance": { "source": null, "revision": null, "importedAt": null }
    }
  },
  "meta": {
    "apiVersion": "1",
    "generatedAt": "2026-08-27T08:15:30+00:00"
  }
}

The example is intentionally shortened. The complete set of returned fields is documented below. Consumers must read the JSON by field name and must not depend on property order.

Article collection response

A request containing only vendor and catalog_number returns HTTP 200 with an array at data.locomotives. Every array element has the same complete structure documented for data.locomotive. meta.count contains the number of returned variants.

{
  "success": true,
  "data": {
    "locomotives": [
      {
        "identity": {
          "id": "piko:40375",
          "vendor": "piko",
          "catalogNumber": "40375",
          "catalogSuffix": "",
          "variantNumber": 1
        },
        "product": { "name": "…" },
        "decoders": []
      }
    ]
  },
  "meta": {
    "apiVersion": "1",
    "generatedAt": "2026-08-28T08:30:00+00:00",
    "count": 1
  }
}

5. Complete field reference

All paths below are relative to data.locomotive.

Identity

Field pathTypeDescription
identity.idstring | nullStable RMDB identifier. Use this value for subsequent requests.
identity.vendorstringTechnical manufacturer name used by RMDB.
identity.catalogNumberstringManufacturer catalogue or article number. Letters and leading zeroes are significant.
identity.catalogSuffixstringCatalogue suffix; an empty string means that no suffix applies.
identity.variantNumberintegerVariant number within the manufacturer/article/suffix combination.

Product

Field pathTypeDescription
product.namestring | nullPublic product name.
product.descriptionstring | nullProduct description as recorded in RMDB.
product.categorystring | nullMain model category.
product.subCategorystring | nullMore specific model category.
product.discontinuedboolean | nullWhether the model is known to be discontinued.
product.production.fromYearinteger | nullFirst known production year.
product.production.toYearinteger | nullLast known production year.

Manufacturer

Field pathTypeDescription
vendor.technicalNamestring | nullCanonical technical manufacturer name.
vendor.displayNamestring | nullManufacturer name for display.
vendor.aliasesstring[]Known alternative manufacturer names.
vendor.activeboolean | nullWhether the manufacturer is currently active in the catalogue.
vendor.websiteUrlstring | nullOfficial manufacturer website.
vendor.supportUrlstring | nullOfficial support website.
vendor.preferredLocalestring | nullPreferred locale for manufacturer material.
vendor.countryCodestring | nullManufacturer country code.
vendor.publicCommentstring | nullPublic manufacturer note.
vendor.linkPolicy.*boolean | nullPermissions recorded for product links, manuals, images, downloads and hotlinking.
vendor.copyright.shortstring | nullShort copyright statement.
vendor.copyright.longstring | nullFull copyright statement.
vendor.copyright.urlstring | nullURL for the applicable copyright or media policy.

Prototype, scale, dimensions and features

Field pathTypeDescription
railway.companystring | nullRailway company or operator.
railway.countrystring | nullRailway country.
railway.classNamestring | nullPrototype class or series.
railway.roadNumberstring | nullIndividual running or road number.
railway.epochstring | nullModel railway epoch.
scale.gaugestring | nullGauge designation, for example N or H0.
scale.ratiostring | nullRecorded scale ratio.
dimensions.lengthMminteger | nullModel length in millimetres.
dimensions.weightGinteger | nullModel weight in grams.
dimensions.bufferToFirstAxleFrontMminteger | nullFront overhang to the first detection axle in millimetres.
dimensions.bufferToFirstAxleRearMminteger | nullRear overhang to the last detection axle in millimetres.
electrical.powerSystemstring | nullRecorded power system.
electrical.digitalProtocolstring | nullRecorded digital protocol.
electrical.decoderDescriptionstring | nullFree-form decoder description from the model record.
features.descriptionstring | nullFree-form feature description.
features.metalBodyboolean | nullMetal body indication.
features.telexboolean | nullRemote coupling indication.
features.smokeboolean | nullSmoke feature indication.
features.interiorLightboolean | nullInterior-light indication.

Technical locomotive data

Field pathTypeDescription
technical.locomotiveTypestring | nullLocomotive or powered-vehicle type.
technical.wheelArrangementstring | nullWheel arrangement.
technical.motor.typestring | nullMotor type.
technical.motor.partNumberstring | nullMotor spare-part number.
technical.motor.shieldPartNumberstring | nullMotor-shield part number.
technical.motor.armaturePartNumberstring | nullArmature part number.
technical.drive.gearTypestring | nullDrive gear type.
technical.drive.gearTeethinteger | nullRecorded gear tooth count.
technical.drive.poweredAxlesinteger | nullNumber of powered axles.
technical.drive.tractionTiresinteger | nullNumber of traction tyres.
technical.conversion.kitstring | nullKnown conversion kit.
technical.conversion.motorstring | nullKnown conversion motor.
technical.factoryDecoder.manufacturerstring | nullFactory decoder manufacturer.
technical.factoryDecoder.modelstring | nullFactory decoder model.
technical.factoryDecoder.interfacestring | nullDecoder interface or connector.
technical.soundboolean | nullWhether sound is recorded for this variant.
technical.functionCountinteger | nullRecorded number of digital functions.
technical.maximumSpeedKmhinteger | nullPrototype maximum speed in kilometres per hour.
technical.minimumRadiusMminteger | nullMinimum supported model radius in millimetres.
technical.pantographsinteger | nullNumber of pantographs.
technical.lighting.cabboolean | nullCab-lighting indication.
technical.lighting.interiorboolean | nullInterior-lighting indication.
technical.smokeGeneratorboolean | nullSmoke-generator indication.
technical.remarksstring | nullTechnical remarks.

Decoders and functions

Field pathTypeDescription
decoders[]object[]Zero or more decoder records for this locomotive variant.
decoders[].numberinteger | nullDecoder sequence number within the model.
decoders[].manufacturerstring | nullDecoder manufacturer.
decoders[].modelstring | nullDecoder model.
decoders[].generationstring | nullDecoder generation.
decoders[].protocolstring | nullDecoder protocol.
decoders[].programmableboolean | nullWhether the decoder is recorded as programmable.
decoders[].defaultAddressinteger | nullFactory default digital address.
decoders[].mobileStationNamestring | nullName used by a Mobile Station, when known.
decoders[].centralStationNamestring | nullName used by a Central Station, when known.
decoders[].functionCountinteger | nullRecorded decoder function count.
decoders[].functions[]object[]Known function descriptions only; each object contains number and description.
decoders[].remarksstring | nullDecoder remarks.
decoders[].provenanceobjectSource, revision and import timestamp for the decoder record.

Media, links, pricing and provenance

Field pathTypeDescription
media.images[]object[]Image metadata: sourceUrl, availableLocally, localFileName and copyright.
media.manuals[]object[]Manual metadata: sourceUrl, availableLocally and localFileName.
links.manufacturerProductUrlstring | nullManufacturer product page.
links.retailers[]object[]Active retailer links with code, productName, productUrl, firstSeenAt and lastSeenAt.
pricing.msrpstring | nullRecorded manufacturer suggested retail price. Returned as text to preserve source precision.
pricing.currencystring | nullCurrency code for MSRP.
remarksstring | nullGeneral RMDB remarks.
provenance.sourcestring | nullSource of the model record.
provenance.revisionstring | nullSource revision.
provenance.importedAtstring | nullSource import timestamp.

6. Missing data and media

  • An unknown scalar value is returned as JSON null. Do not interpret it as zero, false or an empty string.
  • An absent collection is returned as an empty array, for example decoders: [].
  • Only decoder functions with a known description are included in functions[]. Use functionCount separately when present.
  • availableLocally and localFileName describe RMDB holdings. They do not grant permission to reproduce media and they are not download URLs.
  • Always respect the returned manufacturer link and copyright policies. A source URL does not automatically grant hotlinking, downloading or republication rights.

7. Errors

Error responses use the same predictable envelope:

{
  "success": false,
  "error": {
    "code": "locomotive_not_found",
    "message": "The requested locomotive was not found."
  },
  "meta": { "apiVersion": "1" }
}
HTTP statusMeaningTypical action
400Missing, incomplete or invalid identifier.Supply an ID, both article-collection fields, or all four composite-key fields.
401Missing, invalid, revoked or expired API key.Check the Bearer header or request a replacement key.
403The key lacks rmdb:locomotive:read.Request the required scope.
404No locomotive matches the identifier.Verify the RMDB ID, article combination or complete composite key.
405Unsupported HTTP method.Use GET.
409The supplied RMDB identifier is ambiguous.Use the full composite key.
429Rate limit exceeded.Wait for Retry-After and retry with backoff.
500Unexpected server-side failure.Retry later; report persistent failures without sending the API key.

8. Rate limits

The request allowance is assigned per API key. Do not hard-code a universal limit. Every authenticated response exposes the active one-minute window:

X-RateLimit-Limit
Maximum requests in the current one-minute window.
X-RateLimit-Remaining
Requests still available in that window.
X-RateLimit-Reset
Unix timestamp at which the window resets.
Retry-After
Seconds to wait after an HTTP 429 response.

Clients should cache records in their own application where appropriate, avoid repeated reads of an unchanged identifier and use exponential backoff for temporary failures.

9. Compatibility rules

  • The major API version is part of the URL. Breaking changes require a new version such as /api/v2/.
  • Version 1 may gain new optional fields or new values. Clients must ignore unknown properties and must not reject a response merely because it contains more data.
  • Existing field meaning and type will not intentionally change within version 1.
  • Use identity.id as the durable external reference. Catalogue numbers remain strings and must never be normalised numerically.
  • meta.generatedAt is generated in UTC. Other source timestamps should also be treated as UTC unless a future field explicitly carries another offset.

10. Security requirements

  • Use HTTPS only and validate the RailKernel TLS certificate.
  • Store the API key in a secret store or server-side environment variable.
  • Never log the full Authorization header. A short key prefix may be logged for diagnosis.
  • Never send an API key by email, issue tracker, screenshot or source-code repository.
  • Contact RailKernel immediately if a key may have leaked; the key can be revoked without affecting other clients.
  • The API is read-only, but returned data and media metadata remain subject to their recorded source and copyright conditions.