PxApi is a .NET 10.0 Web API for accessing PX statistical datasets. It provides table listings, table metadata and data retrieval with flexible dimension filtering and caching across multiple storage backends (local file system, Azure File Share, Azure Blob Storage).
- Table listing with paging (
/meta/databases/{database}/tables) - Table metadata in JSON-stat 2.0 (
/meta/databases/{database}/tables/{table}) - Data retrieval with filter semantics (code, range, positional) via GET query parameters or POST body (
/data/databases/{database}/tables/{table}) - Content negotiation (JSON-stat 2.0 or CSV) using the
Acceptheader - Cache management endpoints (database level and single table) (
/cache/databases/{database}//cache/databases/{database}/tables/{id}) - Global and per-database caching (file lists, metadata, data, last updated timestamps)
- Feature flags (cache and search endpoint visibility, and search OpenAPI documentation visibility)
- Controller-specific API key authentication for supported controllers
- Multiple storage types: Mounted (local / network), Azure File Share, Azure Blob Storage, Azure Binary Blob Storage
- Query size limits returning HTTP 413 when exceeded
- Metadata search across tables, dimensions, and values (
/meta/search,/meta/databases/{database}/search) - Health check endpoint for database and search backend readiness (
/health) - Info endpoint for application name and version (
/info) - Swagger / OpenAPI documentation with custom schema & document filters
- HEAD and OPTIONS support for discoverability and CORS pre-flight
GET /info
Returns basic application information including the application name and current version. This endpoint is hidden from OpenAPI documentation.
Responses:
200 OKJSON object containing application information
GET /health
Returns overall application health, including configured database connections and the search backend when the Search feature is enabled. This endpoint is hidden from OpenAPI documentation.
Responses:
200 OKall configured dependencies are healthy401 Unauthorizedmissing / invalid API key (whenAuthentication:Healthis configured)503 Service Unavailableone or more configured dependencies are unhealthy
GET /meta/databases?lang=fi
Returns a list of available databases with their metadata.
Query parameters:
lang(optional, defaultfi): Language used for name and description resolution.
Responses:
200 OKJSON array containing database listing items400 Bad Requestrequested language not supported401 Unauthorizedmissing / invalid API key (when authentication configured)
Additional methods:
HEAD /meta/databasesvalidates existence of the database collection resourceOPTIONS /meta/databasesreturns Allow header (GET,HEAD,OPTIONS)
GET /meta/databases/{database}/tables?lang=fi&page=1&pageSize=50
Returns a paged list of tables ordered by PX file name.
Query parameters:
lang(optional, defaultfi): Language used for metadata resolution.page(optional, >=1, default1)pageSize(optional, 1-100, default50)
Responses:
200 OKJSON body containing table listing and paging info400 Bad Requestinvalid paging values or unsupported language401 Unauthorizedmissing / invalid API key (when authentication configured)404 Not Founddatabase missing
Additional methods:
HEAD /meta/databases/{database}/tablesvalidates existence and paging valuesOPTIONS /meta/databases/{database}/tablesreturns Allow header (GET,HEAD,OPTIONS)
GET /meta/databases/{database}/tables/{table}?lang=fi
Returns JSON-stat 2.0 metadata (structure only, no data filtering).
Query parameters:
lang(optional): If omitted uses table default language
Responses:
200 OKJSON-stat 2.0 metadata400 Bad Requestlanguage not available401 Unauthorizedmissing / invalid API key (when authentication configured)404 Not Founddatabase or table missing500 Internal Server Errorunexpected error
Additional methods:
HEAD /meta/databases/{database}/tables/{table}existence & language validation onlyOPTIONS /meta/databases/{database}/tables/{table}returns Allow header (GET,HEAD,OPTIONS)
GET /data/databases/{database}/tables/{table}?filters=TIME:from=2020&filters=TIME:to=2024&filters=REGION:code=001,002
Retrieves data values applying filters to dimensions. Content negotiation support for json and csv:
Accept: application/jsonor*/*-> JSON-stat 2.0Accept: text/csv-> CSV format with containing table description, selected value names and data.
####CSV Export Structure:####
- Table description as A1 cell header
- Stub dimensions (rows) and heading dimensions (columns) based on PX file metadata
- Automatic filtering of single-value elimination/total dimensions for cleaner output
- Formatting of missing values using PX-standard dot codes (
.,..,..., etc.) - Culture-invariant number formatting with period as decimal separator
Filter syntax (GET query parameters):
Each filter supplied via repeated filters query parameter: dimensionCode:filterType=value
Supported filterType values:
codeone or many codes (comma-separated), supports*wildcardfromlower bound for range (supports wildcard*inside value)toupper bound for range (supports wildcard*inside value)firstselects first N positions (positive integer)lastselects last N positions (positive integer)
Rules:
- One filter per dimension.
- Wildcard
*matches zero or more characters in code/from/to values.
POST alternative:
POST /data/databases/{database}/tables/{table} with JSON body mapping dimension codes to filter objects.
Example body:
{
"TIME": { "type": "from", "query": ["2020"] },
"REGION": { "type": "code", "query": ["001", "002"] }
}Query parameters (POST):
langoptional language (defaults to table default)
Responses (GET & POST):
200 OKJSON-stat 2.0 object or CSV text400 Bad Requestinvalid filters / language not available401 Unauthorizedmissing / invalid API key (when authentication configured)404 Not Founddatabase or table missing406 Not AcceptableunsupportedAcceptheader value413 Payload Too Largerequest cell count exceeds configured limit415 Unsupported Media Type(POST invalid content type)
Additional methods:
HEAD /data/databases/{database}/tables/{table}?lang=fiexistence & language validation onlyOPTIONS /data/databases/{database}/tables/{table}returns Allow header (GET,POST,HEAD,OPTIONS)
GET /meta/search?q=population&scope=content&lang=fi&page=1&pageSize=20
Searches across all databases for tables, dimensions, and values.
Requires feature flag SearchController = true in FeatureManagement. When disabled, all search endpoints return 404 and are hidden from OpenAPI documentation.
Query parameters:
q(required): Search query string (max 400 characters).scope(optional): Search scope — one ofcontent,dimension,value,geo,all. When omitted, defaults tocontent(searches title, source, note, content variable, used-for description).lang(optional, default configured language): Language code (ISO 639-1).page(optional, >=1, default1): Page number.pageSize(optional, 1-100, default20): Items per page.
Responses:
200 OKJSON object with search results and paging info400 Bad Requestmissing query, invalid paging, or unsupported language401 Unauthorizedmissing / invalid API key (whenAuthentication:Searchis configured)503 Service Unavailablesearch backend unavailable
Database-scoped search:
GET /meta/databases/{database}/search?q=population&lang=fi
Searches within a single database.
Additional responses:
404 Not Founddatabase not found
Additional methods:
HEAD /meta/searchvalidates the global search endpoint existsHEAD /meta/databases/{database}/searchvalidates the database-scoped search endpoint (returns 404 if database not found)OPTIONS /meta/searchreturns Allow header (GET,HEAD,OPTIONS)OPTIONS /meta/databases/{database}/searchreturns Allow header (GET,HEAD,OPTIONS)
Requires feature flag CacheController = true and valid API key when authentication is enabled. Cache endpoints are always hidden from OpenAPI documentation.
DELETE /cache/databases/{database}clears all cache entries (file list, metadata, data, last updated) for a database.DELETE /cache/databases/{database}/tables/{id}clears all cache entries for a single table.
Responses:
200 OKsuccess message401 Unauthorizedmissing / invalid API key (when authentication configured)404 Not Founddatabase or table not found500 Internal Server Errorunexpected error
Filter object structure:
{
"<DIMENSION_CODE>": {
"type": "code | from | to | first | last",
"query": ["value1", "value2"]
}
}Notes:
first/lastuse a single positive integer value inquery.from/touse one value each.codecan contain multiple codes.
Provided via appsettings.json.
Key sections:
RootUrlBase absolute URL used for generated links & OpenAPI servers.ApplicationInsightsApplication Insights connection configuration:ConnectionStringApplication Insights connection string (can be overridden byAPPLICATIONINSIGHTS_CONNECTION_STRINGenvironment variable)
LoggingStandard .NET logging configuration for Application Insights log level filtering:ApplicationInsights:LogLevel:DefaultMinimum log level to send to Application Insights (Debug, Information, Warning, Error, Critical). Defaults to Information.
DataBasesArray of database definitions:TypeOne ofMounted,FileShare,BlobStorage,BinaryBlobStorageIdUnique idCacheConfigPer-database cache sizing overridesCustomBackend-specific connection settings:Mounted:RootPath— absolute path to the local or network directory containing PX filesFileShare:StoragePath— Azure File Share service URL,ShareName— name of the file shareBlobStorage:StoragePath— Azure Blob Storage service URL,ContainerName— name of the blob containerBinaryBlobStorage:StoragePath— Azure Blob Storage service URL,ContainerName— name of the blob container
CacheGlobal memory cache sizing (applies toMemoryCache):MaxSizeBytes(default 524288000)DefaultDataCellSizeDefaultUpdateTaskSizeDefaultFileListSizeDefaultMetaSizeDefaultAliasSize
QueryLimitsRequest size limits:JsonMaxCells(used for any future JSON minimal format endpoints)JsonStatMaxCells(enforced in current data endpoints; exceeding returns 413)
FeatureManagementFeature flags:CacheControllerEnables cache management endpoints (defaultfalse). Cache endpoints remain hidden from OpenAPI documentation.SearchControllerEnables search endpoints and their OpenAPI documentation (defaultfalse)
AuthenticationController-specific API key settings — see AuthenticationSearchElasticsearch search backend configuration:CloudIdElastic Cloud deployment identifierIndexPrefixIndex name prefix (language code is appended as suffix, e.g.my-index-fi)- The API key is sourced from the
SEARCH_API_KEYenvironment variable (not from appsettings)
OpenApiMetadata (contact, license) for Swagger documentLogOptionsNLog file logging configuration:FolderDirectory for log files (empty disables file logging)SysIdSystem identifier for log entriesLevelMinimum log level for file logging (Debug, Information, Warning, Error, Critical)AuditLogAudit logging settings
Application Insights integration is optional and automatically enabled when a connection string is provided. Log level filtering uses the standard .NET Logging configuration section, keeping it separate from file logging controlled by LogOptions and NLog.
{
"ApplicationInsights": {
"ConnectionString": "InstrumentationKey=your-key;IngestionEndpoint=https://..."
},
"Logging": {
"ApplicationInsights": {
"LogLevel": {
"Default": "Information"
}
}
}
}Connection String Sources (in order of priority):
APPLICATIONINSIGHTS_CONNECTION_STRINGenvironment variableApplicationInsights:ConnectionStringin appsettings.json
Settings:
- ApplicationInsights:ConnectionString: Application Insights connection string. If empty or missing, Application Insights is disabled.
- Logging:ApplicationInsights:LogLevel:Default: Minimum log level to send to Application Insights (Debug, Information, Warning, Error, Critical). Defaults to Information. You can also set per-category log levels (e.g.,
"Microsoft": "Warning").
Environment Variable Configuration:
# Enable Application Insights via environment variable
APPLICATIONINSIGHTS_CONNECTION_STRING="InstrumentationKey=your-key;IngestionEndpoint=https://..."
# Override log level via environment variable
Logging__ApplicationInsights__LogLevel__Default=DebugLogging Architecture:
- File Logs: Controlled by NLog configuration and
LogOptionssection - Application Insights: Connection controlled by
ApplicationInsightssection, log level controlled byLogging:ApplicationInsights:LogLevelsection - Both systems operate independently - you can have file logging without Application Insights, Application Insights without file logging, or both together
PxApi supports optional controller-specific API key authentication. Dedicated configuration is available for Cache, Databases, Tables, Metadata, Data, Search, and Health controllers. When no key is configured for a controller, its endpoints remain publicly accessible.
The hidden InfoController endpoint does not currently have a dedicated authentication section and therefore remains public.
See Authentication for full configuration details, environment variable setup, and security notes.
Key environment variables used by the application:
| Variable | Description |
|---|---|
SEARCH_API_KEY |
API key for authenticating with the Elasticsearch cluster (required for search) |
APPLICATIONINSIGHTS_CONNECTION_STRING |
Application Insights connection string (optional, overrides appsettings value) |
Global cache size limit controlled via Cache.MaxSizeBytes. Individual item sizes use defaults above or per-database overrides. Cached entities:
- File lists
- Metadata objects
- Data arrays
- Last updated timestamps (per PX file)
- Mounted (local / network path) direct file access
- Azure File Share via Azure Storage SDK
- Azure Blob Storage via Azure Storage SDK
- Azure Binary Blob Storage via Azure Storage SDK (binary-optimized blob access)
Specify desired format with Accept header:
application/json-> JSON-stat 2.0text/csv-> Table description, selected value names and data in CSV format*/*or empty -> JSON-stat 2.0
Central exception handling returns standardized 500 responses and 400 responses for invalid requests. Specific endpoints return 400/404/406/413/415 as described.
- Configure
appsettings.jsonwith databases, cache settings, and optionally authentication. - Run the application.
- Access Swagger UI at root (
/) for interactive documentation (openapi/document.json).
Apache License 2.0. See docs/LICENSE.md.