openapi: 3.0.0 info: description: >- Metadata Editor API Find out more about Metadata Editor at [https://github.com/worldbank/metadata-editor](https://github.com/worldbank/metadata-editor). version: 1.0.0 title: Metadata Editor API x-logo: url: "" backgroundColor: "#FFFFFF" altText: "" servers: - url: https://{host}/index.php/api/ description: HTTPS Server variables: host: default: localhost description: API server host - url: http://{host}/index.php/api/ description: HTTP Server variables: host: default: localhost description: API server host tags: - name: Projects description: Create, update projects - name: Microdata description: Manage microdata projects - name: Timeseries description: Manage timeseries projects - name: Timeseries-db description: Manage timeseries database projects - name: Geospatial description: Manage geospatial projects - name: Document description: Manage document projects - name: Table description: Manage table projects - name: Image description: Manage image projects - name: Script description: Manage scripts - name: Video description: Manage video projects - name: External resources description: Manage external resources and files for projects - name: Collections description: Collections - name: Templates description: Templates - name: SDMX description: SDMX - name: Admin metadata description: Administrative Metadata - name: Admin metadata templates description: Administrative Metadata templates - name: Publish projects description: Publish projects to NADA catalogs - name: Catalog connections description: Manage catalog connections - name: Issues description: Manage project metadata issues - name: Jobs description: Background jobs - name: Codelists description: Global codelist catalogue (registry) - name: Data Structures description: Global DSD catalogue (registry) - name: Indicator DSD description: Project-level DSD binding, validation, and data import x-tagGroups: - name: Projects tags: - Projects - name: Microdata tags: - Microdata - name: Timeseries tags: - Timeseries - name: Timeseries-db tags: - Timeseries-db - name: Geospatial tags: - Geospatial - name: Document tags: - Document - name: Table tags: - Table - name: Image tags: - Image - name: Script tags: - Script - name: Video tags: - Video - name: External resources tags: - External resources - name: Collections tags: - Collections - name: Templates tags: - Templates - name: SDMX tags: - SDMX - name: Admin metadata tags: - Admin metadata - Admin metadata templates - name: Publish projects tags: - Publish projects - name: Catalog connections tags: - Catalog connections - name: Issues tags: - Issues - name: Jobs tags: - Jobs - name: Registry tags: - Codelists - Data Structures - name: Indicator DSD tags: - Indicator DSD paths: /issues: get: tags: - Issues summary: List all issues description: List all issues (filtered by user permissions) operationId: listIssues parameters: - name: status in: query description: Status filter (can be comma-separated) schema: type: string - name: category in: query description: Category filter schema: type: string - name: severity in: query description: Severity filter schema: type: string - name: applied in: query description: Applied filter schema: type: integer - name: field_path in: query description: Field path filter schema: type: string - name: id in: query description: Issue ID filter (exact match) schema: type: integer - name: project_id in: query description: Project ID filter (exact match) schema: type: integer - name: limit in: query description: Page size schema: type: integer default: 50 - name: offset in: query description: Offset for pagination schema: type: integer default: 0 - name: sort_by in: query description: Sort field schema: type: string default: created - name: sort_order in: query description: Sort order schema: type: string default: DESC responses: "200": description: successful operation "400": description: Bad request security: - ApiKeyAuth: [] post: tags: - Issues summary: Create new issue description: Create a new issue for a project operationId: createIssue requestBody: content: application/json: schema: type: object required: - project_id - title properties: project_id: type: integer title: type: string description: type: string category: type: string field_path: type: string severity: type: string current_metadata: type: object suggested_metadata: type: object source: type: string responses: "201": description: Issue created successfully "400": description: Bad request security: - ApiKeyAuth: [] "/issues/{id}": get: tags: - Issues summary: Get single issue description: Get issue details by ID operationId: getIssue parameters: - name: id in: path required: true schema: type: integer responses: "200": description: successful operation "400": description: Issue not found security: - ApiKeyAuth: [] put: tags: - Issues summary: Update issue description: Update an existing issue operationId: updateIssue parameters: - name: id in: path required: true schema: type: integer requestBody: content: application/json: schema: type: object properties: title: type: string description: type: string category: type: string severity: type: string assigned_to: type: integer notes: type: string responses: "200": description: Issue updated successfully "400": description: Bad request security: - ApiKeyAuth: [] delete: tags: - Issues summary: Delete issue description: Delete an issue by ID operationId: deleteIssue parameters: - name: id in: path required: true schema: type: integer responses: "200": description: Issue deleted successfully "400": description: Bad request security: - ApiKeyAuth: [] "/issues/delete/{id}": post: tags: - Issues summary: Delete issue (POST alias) description: Delete an issue by ID (POST alias for DELETE) operationId: deleteIssuePost parameters: - name: id in: path required: true schema: type: integer responses: "200": description: Issue deleted successfully "400": description: Bad request security: - ApiKeyAuth: [] "/issues/project/{sid}": get: tags: - Issues summary: List issues for a project description: Get all issues for a specific project operationId: listProjectIssues parameters: - name: sid in: path required: true description: Project SID schema: type: string - name: status in: query description: Status filter (can be comma-separated) schema: type: string - name: category in: query description: Category filter schema: type: string - name: severity in: query description: Severity filter schema: type: string - name: applied in: query description: Applied filter schema: type: integer - name: field_path in: query description: Field path filter schema: type: string - name: limit in: query description: Page size schema: type: integer default: 50 - name: offset in: query description: Offset for pagination schema: type: integer default: 0 - name: sort_by in: query description: Sort field schema: type: string default: created - name: sort_order in: query description: Sort order schema: type: string default: DESC responses: "200": description: successful operation "400": description: Bad request security: - ApiKeyAuth: [] "/issues/project/{sid}/stats": get: tags: - Issues summary: Get issue statistics description: Get issue statistics for a specific project operationId: getProjectIssueStats parameters: - name: sid in: path required: true description: Project SID schema: type: string responses: "200": description: successful operation "400": description: Bad request security: - ApiKeyAuth: [] "/issues/apply/{id}": post: tags: - Issues summary: Apply suggested changes description: Apply suggested metadata changes for an issue operationId: applyIssueChanges parameters: - name: id in: path required: true schema: type: integer responses: "200": description: Changes applied successfully "400": description: Bad request security: - ApiKeyAuth: [] "/issues/status/{id}": post: tags: - Issues summary: Update status description: Update issue status operationId: updateIssueStatus parameters: - name: id in: path required: true schema: type: integer requestBody: content: application/json: schema: type: object required: - status properties: status: type: string responses: "200": description: Status updated successfully "400": description: Bad request security: - ApiKeyAuth: [] "/issues/bulk_status": post: tags: - Issues summary: Bulk update status description: Bulk update status for multiple issues operationId: bulkUpdateIssueStatus requestBody: content: application/json: schema: type: object required: - ids - status properties: ids: type: array items: type: integer status: type: string responses: "200": description: Statuses updated successfully "400": description: Bad request security: - ApiKeyAuth: [] /editor: get: tags: - Projects summary: Search description: Search and browse projects operationId: EditorProjects parameters: - name: keywords in: query title: Project search keywords description: Keywords for searching project by title and IDNO schema: type: string - name: type in: query title: Project data type description: Project data type e.g. Microdata, Document, Table, ... schema: type: string enum: - microdata - document - table - timeseries - timeseries-db - geospatial - image - script - video - name: date_start in: query title: Start date description: Search for projects changed on or after this date. Use the date format `YYYY-MM-DD` e.g. 2020-01-01 schema: type: string format: date - name: date_end in: query title: End date description: Search for projects changed on or before this date. Use the date format `YYYY-MM-DD` e.g. 2020-01-20 schema: type: string format: date - name: offset in: query title: Offset description: Offset for pagination e.g. 10 to skip first 10 records schema: type: integer - name: limit in: query title: Page size description: Page size e.g. 10 to show 10 records schema: type: integer - name: sort_by in: query title: Sort results description: Sort results schema: type: string enum: - title_asc - title_desc - updated_asc - updated_desc - name: collection in: query title: Collections description: Filter by collections. Provide comma-separated collection IDs e.g. 1,2,3 schema: type: string - name: exclude_collections in: query title: Exclude collections description: When set to 'true', negates the collection filter to exclude the selected collections instead of including them schema: type: string enum: - "true" - "false" - name: ownership in: query title: Ownership filter description: Filter by project ownership schema: type: string enum: - self - shared - self,shared - name: users in: query title: Users filter description: Filter projects by users who created or modified them. Provide comma-separated user IDs e.g. 1,2,3 schema: type: string responses: "200": description: successful operation "400": description: Bad input "/editor/{id}": get: tags: - Projects summary: Get project by ID description: Get study level metadata for a project operationId: singleProject parameters: - name: id in: path title: Project unique ID description: Project unique ID number required: true schema: type: string - name: version in: query title: Version number description: Get project by specific version number (e.g. 1.0.0) required: false schema: type: string responses: "200": description: successful operation "/editor/json{id}": get: tags: - Projects summary: Get project JSON description: > Get project metadata as JSON. For microdata/survey projects, the response includes all variables by default. Use `exclude_variables=1` to omit variables from the response (useful when only study-level metadata is needed, e.g. for comparison workflows). operationId: singleProjectJSON parameters: - name: id in: path description: Project ID or IDNO required: true schema: type: string - name: version in: query description: Get metadata for a specific version number (e.g. 1.0.0) required: false schema: type: string - name: exclude_variables in: query description: > Exclude variables from the response. Only applicable to microdata/survey projects. When set to `1`, the `variables` array is omitted from the JSON output. The `data_files` array is still included. required: false schema: type: integer enum: [0, 1] default: 0 - name: exclude_private_fields in: query description: > Exclude fields marked as private in the project template. Set to `1` to omit private fields from the response. required: false schema: type: integer enum: [0, 1] default: 0 - name: external_resources in: query description: > Include external resources (documentation files) in the response. Set to `1` to append the `external_resources` array to the JSON output. required: false schema: type: integer enum: [0, 1] default: 0 - name: admin_metadata in: query description: > Include administrative metadata in the response. Set to `1` to append the `admin_metadata` object to the JSON output. required: false schema: type: integer enum: [0, 1] default: 0 responses: "200": description: successful operation "400": description: Bad request - project not found or access denied "/editor/json-field/{id}": get: tags: - Projects summary: Get project JSON field by JSON Pointer description: > Returns a single value from the same project JSON document produced by Get project JSON (`/editor/json/{id}`), addressed by a JSON Pointer (RFC 6901). Examples: `/idno`, `/type`, `/identification/title`, `/variables/0/name` (when variables are included in the export). operationId: projectJsonField parameters: - name: id in: path description: Project ID or IDNO required: true schema: type: string - name: path in: query description: > JSON Pointer (RFC 6901) to the value, starting with `/`. Must be URL-encoded if it contains reserved characters (e.g. `~0`, `~1` for `~` and `/` in keys). required: true schema: type: string - name: version in: query description: Use metadata for a specific version number (e.g. 1.0.0) required: false schema: type: string - name: exclude_variables in: query description: Same as Get project JSON; when `1`, `/variables/...` is not available. required: false schema: type: integer enum: [0, 1] default: 0 - name: exclude_private_fields in: query required: false schema: type: integer enum: [0, 1] default: 0 - name: external_resources in: query required: false schema: type: integer enum: [0, 1] default: 0 - name: admin_metadata in: query required: false schema: type: integer enum: [0, 1] default: 0 responses: "200": description: Value resolved or path missing in document content: application/json: schema: type: object properties: status: type: string enum: [success] path: type: string found: type: boolean value: description: Present when found is true; null when found is false "400": description: Bad request — missing path, invalid pointer syntax, project not found, or access denied security: - ApiKeyAuth: [] "/editor/generate_pdf/{id}": get: tags: - Projects summary: Generate project PDF documentation description: Generate PDF documentation for a project. Returns status and result information. operationId: generateProjectPDF parameters: - name: id in: path title: Project unique ID description: Project ID or IDNO required: true schema: type: string - name: include_private_fields in: query title: Include private fields description: Include private fields in the PDF (0 = exclude, 1 = include). Default is 0. required: false schema: type: integer enum: - 0 - 1 - name: template_uid in: query title: Template UID description: Template UID to use for PDF generation required: false schema: type: string - name: include_external_resources in: query title: Include external resources description: Include external resources in the PDF (0 = exclude, 1 = include). Default is 0. required: false schema: type: integer enum: - 0 - 1 responses: "200": description: PDF generation successful content: application/json: schema: type: object properties: status: type: string example: success result: type: object description: PDF generation result information "400": description: Bad request - project not found or generation failed content: application/json: schema: type: object properties: status: type: string example: failed message: type: string security: - ApiKeyAuth: [] "/editor/delete/{id}": get: tags: - Projects summary: Delete project by ID description: Delete project operationId: deleteProject parameters: - name: id in: path title: Project unique ID description: Project unique ID number required: true schema: type: string responses: "200": description: successful operation security: - ApiKeyAuth: [] "/editor/duplicate/{id}": post: tags: - Projects summary: Duplicate project description: > Create a new editable copy of a project as an independent main project. Copies metadata, data files (including indicator CSV in the project folder), variables, variable groups, external resources, thumbnail, and indicator DSD binding (without DuckDB publish state). Does not copy version history, collaborators, collections, tags, or published DuckDB timeseries data. The new project receives a generated UUID idno and a title with the suffix " (copy)". operationId: duplicateProject parameters: - name: id in: path description: Source project ID or IDNO required: true schema: type: string responses: "200": description: Project duplicated successfully content: application/json: schema: $ref: "#/components/schemas/DuplicateProjectResponse" "400": description: Bad request content: application/json: schema: type: object properties: status: type: string example: failed message: type: string security: - ApiKeyAuth: [] "/editor/{id}/data_files": get: tags: - Microdata summary: List data files description: List all data files for a Microdata type project operationId: listDataFiles parameters: - name: id in: path title: Study unique ID description: Study unique ID number required: true schema: type: string responses: "200": description: successful operation "/editor/{id}/variables": get: tags: - Microdata summary: List variables description: > List variables for a microdata/survey project. Returns `name`, `labl`, `fid`, `vid`, `field_dtype`, and `sort_order` by default. Set `detailed=1` to include the full variable metadata blob. Supports pagination via `limit` and `offset`. operationId: listVariables parameters: - name: id in: path description: Project ID (numeric) required: true schema: type: integer - name: detailed in: query description: > Set to `1` to return the full variable metadata (all fields). Defaults to `0` (returns only plain-text DB columns: name, labl, fid, vid, field_dtype, sort_order). required: false schema: type: integer enum: [0, 1] default: 0 - name: limit in: query description: > Maximum number of variables to return. Omit or set to `0` to return all variables (no pagination). required: false schema: type: integer - name: offset in: query description: Number of variables to skip before returning results. Used for pagination. required: false schema: type: integer default: 0 responses: "200": description: successful operation "/editor/{id}/variables/{varId}": get: tags: - Microdata summary: Find variable description: Get a single variable metadata operationId: findSingleVariable parameters: - name: id in: path title: Study unique ID description: Study unique ID number required: true schema: type: string - name: varId in: path title: Variable ID description: Variable ID required: true schema: type: string responses: "200": description: successful operation content: application/json: schema: type: object "/editor/sdmx/{id}": post: tags: - SDMX summary: SDMX Metadata report set description: Create a new SDMX metadata report set operationId: getMetadatasetSDMX requestBody: content: application/json: schema: $ref: sdmx-json-metadata-schema.json required: true responses: "200": description: successful operation content: application/json: schema: $ref: sdmx-json-metadata-schema.json security: - ApiKeyAuth: [] /importproject/: post: tags: - Projects summary: Import project description: Create a project by importing metadata (XML/JSON) or project zip package operationId: importProject requestBody: content: application/x-www-form-urlencoded: schema: type: object properties: type: description: "Project type e.g. microdata, document, table, timeseries, etc " type: string file: description: Project file (XML, JSON or package zip) type: string format: binary required: - type - file required: true responses: "200": description: successful operation security: - ApiKeyAuth: [] /editor/create/survey: post: tags: - Microdata summary: Create Microdata description: Create a new microdata project operationId: createSurvey requestBody: required: true content: application/json: schema: allOf: - $ref: survey-schema.json - $ref: "#/components/schemas/CreateProjectOverwrite" responses: "200": description: successful operation content: application/json: schema: $ref: survey-schema.json security: - ApiKeyAuth: [] "/editor/update/survey/{id}": post: tags: - Microdata summary: Update Microdata description: Update Microdata project operationId: updateSurvey parameters: - in: path name: id description: Project ID or IDNO required: true schema: type: string format: string requestBody: $ref: "#/components/requestBodies/survey-schema.json" responses: "200": description: successful operation content: application/json: schema: $ref: survey-schema.json security: - ApiKeyAuth: [] "/editor/patch/{project-type}/{id}": post: tags: - Projects - Microdata - Timeseries - Timeseries-db - Geospatial - Document - Table - Image - Script - Video summary: Partial Metadata update description: Add, update, delete or replace parts of a project metadata operationId: patchProject parameters: - in: path name: id description: Project ID or IDNO required: true schema: type: string format: string - in: path name: project-type description: Project type required: true schema: type: string format: string enum: - survey - timeseries - timeseries-db - geospatial - document - table - image - script - video requestBody: content: application/json: schema: $ref: json-patch-schema.json required: true responses: "200": description: successful operation security: - ApiKeyAuth: [] /editor/create/timeseries: post: tags: - Timeseries summary: Create Timeseries description: Create a new timeseries project operationId: createTimeseries requestBody: required: true content: application/json: schema: allOf: - $ref: timeseries-schema.json - $ref: "#/components/schemas/CreateProjectOverwrite" responses: "200": description: successful operation content: application/json: schema: $ref: timeseries-schema.json security: - ApiKeyAuth: [] "/editor/update/timeseries/{id}": post: tags: - Timeseries summary: Update Timeseries description: Update Timeseries project operationId: updateTimseries parameters: - in: path name: id description: Project ID required: true schema: type: string format: string requestBody: $ref: "#/components/requestBodies/timeseries-schema.json" responses: "200": description: successful operation content: application/json: schema: $ref: timeseries-schema.json security: - ApiKeyAuth: [] /editor/create/timeseries-db: post: tags: - Timeseries-db summary: Create Timeseries Database description: Create a new timeseries database project operationId: createTimeseriesDb requestBody: required: true content: application/json: schema: allOf: - $ref: timeseries-db-schema.json - $ref: "#/components/schemas/CreateProjectOverwrite" responses: "200": description: successful operation content: application/json: schema: $ref: timeseries-db-schema.json security: - ApiKeyAuth: [] "/editor/update/timeseries-db/{id}": post: tags: - Timeseries-db summary: Update Timeseries database description: Update Timeseries database project operationId: updateTimseriesDb parameters: - in: path name: id description: Project ID required: true schema: type: string format: string requestBody: $ref: "#/components/requestBodies/timeseries-db-schema.json" responses: "200": description: successful operation content: application/json: schema: $ref: timeseries-db-schema.json security: - ApiKeyAuth: [] /editor/create/geospatial: post: tags: - Geospatial summary: Create Geospatial description: Create a new geospatial project operationId: createGeoSpatial requestBody: required: true content: application/json: schema: allOf: - $ref: geospatial-schema.json - $ref: "#/components/schemas/CreateProjectOverwrite" responses: "200": description: successful operation content: application/json: schema: $ref: geospatial-schema.json security: - ApiKeyAuth: [] "/editor/update/geospatial/{id}": post: tags: - Geospatial summary: Update Geospatial description: Update Geospatial project operationId: updateGeospatial parameters: - in: path name: id description: Project ID required: true schema: type: string format: string requestBody: $ref: "#/components/requestBodies/geospatial-schema.json" responses: "200": description: successful operation content: application/json: schema: $ref: geospatial-schema.json security: - ApiKeyAuth: [] /editor/create/document: post: tags: - Document summary: Create Document description: Create a new document project operationId: createDocument requestBody: required: true content: application/json: schema: allOf: - $ref: document-schema.json - $ref: "#/components/schemas/CreateProjectOverwrite" responses: "200": description: successful operation content: application/json: schema: $ref: document-schema.json security: - ApiKeyAuth: [] "/editor/update/document/{id}": post: tags: - Document summary: Update Document description: Update document project operationId: updateDocument parameters: - in: path name: id description: Project ID required: true schema: type: string format: string requestBody: $ref: "#/components/requestBodies/document-schema.json" responses: "200": description: successful operation content: application/json: schema: $ref: document-schema.json security: - ApiKeyAuth: [] /editor/create/table: post: tags: - Table summary: Create Table description: Create a new table project operationId: createTable requestBody: required: true content: application/json: schema: allOf: - $ref: table-schema.json - $ref: "#/components/schemas/CreateProjectOverwrite" responses: "200": description: successful operation content: application/json: schema: $ref: table-schema.json security: - ApiKeyAuth: [] "/editor/update/table/{id}": post: tags: - Table summary: Update Table description: Update table project operationId: updateTable parameters: - in: path name: id description: Project ID required: true schema: type: string format: string requestBody: $ref: "#/components/requestBodies/table-schema.json" responses: "200": description: successful operation content: application/json: schema: $ref: table-schema.json security: - ApiKeyAuth: [] /editor/create/image: post: tags: - Image summary: Create Image description: Create a new image project operationId: createImage requestBody: required: true content: application/json: schema: allOf: - $ref: image-schema.json - $ref: "#/components/schemas/CreateProjectOverwrite" responses: "200": description: successful operation content: application/json: schema: $ref: image-schema.json security: - ApiKeyAuth: [] "/editor/update/image/{id}": post: tags: - Image summary: Update Image description: Update image project operationId: updateImage parameters: - in: path name: id description: Project ID required: true schema: type: string format: string requestBody: $ref: "#/components/requestBodies/image-schema.json" responses: "200": description: successful operation content: application/json: schema: $ref: image-schema.json security: - ApiKeyAuth: [] /editor/create/video: post: tags: - Video summary: Create Video description: Create a new video project operationId: createVideo requestBody: required: true content: application/json: schema: allOf: - $ref: video-schema.json - $ref: "#/components/schemas/CreateProjectOverwrite" responses: "200": description: successful operation content: application/json: schema: $ref: video-schema.json security: - ApiKeyAuth: [] "/editor/update/video/{id}": post: tags: - Video summary: Update Video description: Update video project operationId: updateVideo parameters: - in: path name: id description: Project ID required: true schema: type: string format: string requestBody: $ref: "#/components/requestBodies/video-schema.json" responses: "200": description: successful operation content: application/json: schema: $ref: video-schema.json security: - ApiKeyAuth: [] /editor/create/script: post: tags: - Script summary: Create Script description: Create a new script type project operationId: createScript requestBody: required: true content: application/json: schema: allOf: - $ref: script-schema.json - $ref: "#/components/schemas/CreateProjectOverwrite" responses: "200": description: successful operation content: application/json: schema: $ref: script-schema.json security: - ApiKeyAuth: [] "/editor/update/script/{id}": post: tags: - Script summary: Update Script description: Update script project operationId: updateScript parameters: - in: path name: id description: Project ID required: true schema: type: string format: string requestBody: $ref: "#/components/requestBodies/script-schema.json" responses: "200": description: successful operation content: application/json: schema: $ref: script-schema.json security: - ApiKeyAuth: [] "/data/datafile/{id}": post: tags: - Microdata summary: Upload microdata data file description: Upload a microdata data file (CSV, DTA, SAV, etc.). The file will be processed and metadata extracted automatically. operationId: uploadDatafile parameters: - in: path name: id description: Project ID or IDNO required: true schema: type: string requestBody: content: multipart/form-data: schema: type: object properties: file: description: Data file to upload (CSV, Stata DTA, SPSS SAV, etc.) type: string format: binary overwrite: description: "Overwrite existing data file if it exists. Valid values: `0` (do not overwrite), `1` (overwrite)" type: integer enum: - 0 - 1 default: 0 store_data: description: Whether to store the data file or just metadata. Use 'store' to keep data accessible, 'remove' to delete data after metadata extraction. type: string enum: - store - remove description: type: string description: File description (datafile-schema.json) producer: type: string maxLength: 255 description: File producer data_checks: type: string description: Processing / data checks missing_data: type: string description: Missing data documentation version: type: string maxLength: 255 description: File version notes: type: string description: File notes required: - file - store_data required: true responses: "200": description: Data file uploaded successfully content: application/json: schema: type: object properties: status: type: string example: success result: type: object properties: uploaded: type: object properties: uploaded_file_name: type: string base64: type: string file_id: type: string "400": description: Bad request - project not found, file upload failed, or invalid parameters security: - ApiKeyAuth: [] "/data/replace_datafile/{sid}/{file_id}": post: tags: - Microdata summary: Replace existing data file description: Replace an existing microdata data file with a new version. The system will automatically detect variable changes (added, removed, updated). operationId: replaceDatafile parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: file_id description: Data file ID to replace required: true schema: type: string requestBody: content: multipart/form-data: schema: type: object properties: file: description: New data file type: string format: binary required: - file required: true responses: "200": description: Data file replaced successfully content: application/json: schema: type: object properties: status: type: string example: success message: type: string example: 3 variable(s) removed, 10 variable(s) updated, 2 new variable(s) added result: type: object "400": description: Bad request - project not found, data file not found, or replacement failed security: - ApiKeyAuth: [] "/data/generate_summary_stats_queue/{sid}/{file_id}": get: tags: - Microdata summary: Generate summary statistics description: Generate summary statistics and frequencies for all variables in a data file. This is queued as a background job. operationId: generateSummaryStats parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: file_id description: Data file ID required: true schema: type: string responses: "200": description: Summary statistics generation queued successfully "400": description: Bad request - project not found or data file not found security: - ApiKeyAuth: [] post: tags: - Microdata summary: Generate summary statistics (POST) description: Generate summary statistics and frequencies for all variables in a data file. This is queued as a background job. operationId: generateSummaryStatsPost parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: file_id description: Data file ID required: true schema: type: string responses: "200": description: Summary statistics generation queued successfully "400": description: Bad request - project not found or data file not found security: - ApiKeyAuth: [] "/data/generate_summary_stats_variable/{sid}/{file_id}": post: tags: - Microdata summary: Generate statistics for specific variables description: Generate summary statistics and frequencies for specific variables in a data file operationId: generateVariableStats parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: file_id description: Data file ID required: true schema: type: string requestBody: content: application/json: schema: type: object required: - var_names properties: var_names: type: array items: type: string description: Array of variable names to generate statistics for required: true responses: "200": description: Variable statistics generated successfully content: application/json: schema: type: object properties: status: type: string example: success result: type: string variables_imported: type: object response: type: object "400": description: Bad request - project not found, data file not found, or invalid parameters security: - ApiKeyAuth: [] "/data/generate_csv/{sid}/{file_id}": get: tags: - Microdata summary: Generate CSV from data file description: Convert a data file (DTA, SAV, etc.) to CSV format. This is queued as a background job. operationId: generateCSV parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: file_id description: Data file ID required: true schema: type: string responses: "200": description: CSV generation queued successfully "400": description: Bad request - project not found or data file not found security: - ApiKeyAuth: [] "/datafiles/columns_diff/{sid}/{file_id}": get: tags: - Microdata summary: Get columns diff (sync with CSV) description: > Get the difference between variable names in metadata and column headers in the data file (CSV). Use this to sync metadata with the CSV (e.g. identify variables in DB not in CSV, or columns in CSV not in DB). operationId: getColumnsDiff parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: file_id description: Data file ID required: true schema: type: string responses: "200": description: successful operation content: application/json: schema: type: object properties: status: type: string example: success columns_diff: type: object description: Sync info (e.g. columns_in_db_not_in_csv, in_sync) "400": description: Bad request - project not found or data file not found security: - ApiKeyAuth: [] "/datafiles/invalid_variable_names/{sid}/{file_id}": get: tags: - Microdata summary: Get invalid variable names description: > Get list of variables that do not meet Stata/SPSS naming rules (e.g. leading underscore, invalid characters, starts with number, too long). Used for bulk-fix workflows. operationId: getInvalidVariableNames parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: file_id description: Data file ID required: true schema: type: string responses: "200": description: successful operation content: application/json: schema: type: object properties: status: type: string example: success invalid_names: type: array description: List of { name, message, reason } for each invalid variable items: type: object properties: name: type: string message: type: string reason: type: string enum: - leading_underscore - invalid_chars - starts_with_number - too_long - empty "400": description: Bad request - project not found or data file not found security: - ApiKeyAuth: [] "/upload/{sid}": post: tags: - Microdata summary: Upload file (with chunked upload support) description: > Upload files with support for both normal and chunked uploads. Chunked uploads are useful for large files. **For normal uploads**: Send file as multipart/form-data with field name 'file' **For chunked uploads**: Include these headers: - X-Chunk-Index: Current chunk number (0-based) - X-Total-Chunks: Total number of chunks - X-Upload-ID: Unique identifier for this upload - X-File-Name: Original filename - X-File-Size: Total file size in bytes - X-Is-Final-Chunk: 1 for final chunk, 0 otherwise Send each chunk as multipart/form-data with field name 'chunk' operationId: uploadFile parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: header name: X-Chunk-Index description: Current chunk index (0-based) for chunked uploads required: false schema: type: integer - in: header name: X-Total-Chunks description: Total number of chunks for chunked uploads required: false schema: type: integer - in: header name: X-Upload-ID description: Unique upload identifier for chunked uploads required: false schema: type: string - in: header name: X-File-Name description: Original filename for chunked uploads required: false schema: type: string - in: header name: X-File-Size description: Total file size in bytes for chunked uploads required: false schema: type: integer - in: header name: X-Is-Final-Chunk description: Whether this is the final chunk (0 or 1) for chunked uploads required: false schema: type: integer requestBody: content: multipart/form-data: schema: type: object properties: file: description: File to upload (for normal uploads) type: string format: binary chunk: description: Chunk data (for chunked uploads) type: string format: binary responses: "200": description: File uploaded successfully (or chunk received for chunked uploads) content: application/json: schema: type: object properties: status: type: string enum: - success - chunk_received upload_method: type: string enum: - normal - chunked upload_id: type: string file_name: type: string file_path: type: string file_size: type: integer file_type: type: string chunk_index: type: integer chunks_received: type: integer total_chunks: type: integer percent_complete: type: number message: type: string "400": description: Bad request - project not found, no file uploaded, or upload failed security: - ApiKeyAuth: [] "/upload/status/{sid}/{upload_id}": get: tags: - Microdata summary: Get upload status description: Get the current status of a chunked upload operationId: getUploadStatus parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: upload_id description: Upload ID required: true schema: type: string responses: "200": description: Upload status retrieved successfully content: application/json: schema: type: object properties: chunks_received: type: integer total_chunks: type: integer percent_complete: type: number "400": description: Bad request - upload ID not found security: - ApiKeyAuth: [] "/upload/{sid}/{upload_id}": delete: tags: - Microdata summary: Cancel chunked upload description: Cancel an in-progress chunked upload and cleanup temporary files operationId: cancelUpload parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: upload_id description: Upload ID to cancel required: true schema: type: string responses: "200": description: Upload cancelled successfully content: application/json: schema: type: object properties: status: type: string example: success message: type: string example: Upload cancelled successfully "400": description: Bad request - upload ID not found security: - ApiKeyAuth: [] "/editor/collections/{id}": get: tags: - Projects - Collections summary: Get collections by project description: Get a list of collections by project ID operationId: getCollectionsByProject parameters: - name: id in: path title: Project unique ID description: Project unique ID number required: true schema: type: string responses: "200": description: successful operation "/editor/history/{id}": get: tags: - Projects summary: Get project metadata change history description: > Paginated audit log of metadata changes for a project (study metadata saves and JSON patch operations). Each entry may include a v1 change record with `version`, `scope`, `summary`, and `patch` (list of path-level add/remove/replace operations with old/new values). operationId: getProjectHistory parameters: - name: id in: path description: Project ID or IDNO required: true schema: type: string - name: limit in: query description: Page size (maximum 100) schema: type: integer default: 15 minimum: 1 maximum: 100 - name: offset in: query description: Number of entries to skip schema: type: integer default: 0 minimum: 0 responses: "200": description: successful operation content: application/json: schema: $ref: "#/components/schemas/ProjectHistoryResponse" "400": description: Bad request security: - ApiKeyAuth: [] /collections: get: tags: - Collections summary: List collections description: List collections operationId: listCollections responses: "200": description: successful operation content: application/json: schema: $ref: "#/components/schemas/Collection" security: - ApiKeyAuth: [] post: tags: - Collections summary: Create collection description: Create a new collection operationId: createCollection requestBody: $ref: "#/components/requestBodies/Collection" responses: "200": description: successful operation content: application/json: schema: $ref: "#/components/schemas/Collection" security: - ApiKeyAuth: [] "/collections/update/{collectionId}": post: tags: - Collections summary: Update collection description: Update a collection operationId: updateCollection requestBody: $ref: "#/components/requestBodies/Collection" responses: "200": description: successful operation content: application/json: schema: $ref: "#/components/schemas/Collection" security: - ApiKeyAuth: [] /collections/copy: post: tags: - Collections summary: Copy collection description: Copy collection operationId: copyCollection requestBody: content: application/json: schema: $ref: "#/components/schemas/CopyCollection" required: true responses: "200": description: successful operation content: application/json: schema: $ref: "#/components/schemas/CopyCollection" security: - ApiKeyAuth: [] /collections/move: post: tags: - Collections summary: Move collection description: Move collection operationId: moveCollection requestBody: content: application/json: schema: $ref: "#/components/schemas/MoveCollection" required: true responses: "200": description: successful operation content: application/json: schema: $ref: "#/components/schemas/MoveCollection" security: - ApiKeyAuth: [] /collections/permissions: get: tags: - Collections summary: Get user's collection permissions description: Get all collections with user's permission levels for view, edit, and admin access operationId: getUserCollectionPermissions responses: "200": description: successful operation content: application/json: schema: $ref: "#/components/schemas/UserCollectionPermissions" security: - ApiKeyAuth: [] "/collections/{id}": get: tags: - Collections summary: Get collection by ID description: Get collection by ID operationId: getCollectionById parameters: - name: id in: path title: Collection ID description: Collection ID required: true schema: type: string responses: "200": description: successful operation content: application/json: schema: $ref: "#/components/schemas/CollectionList" security: - ApiKeyAuth: [] delete: tags: - Collections summary: Delete collection description: Delete a collection operationId: deleteCollectionById parameters: - name: id in: path title: Collection ID description: Collection ID required: true schema: type: string responses: "200": description: successful operation security: - ApiKeyAuth: [] /collections/projects: post: tags: - Collections summary: List projects by collection description: List projects by collection operationId: listProjectsByCollection parameters: - in: query name: collection_id required: true description: Collection ID schema: type: integer responses: "200": description: successful operation security: - ApiKeyAuth: [] /collections/add_projects: post: tags: - Collections summary: Add projects to collection description: Add projects to collection operationId: addProjectsToCollection requestBody: $ref: "#/components/requestBodies/AddProjectsToCollection" responses: "200": description: successful operation content: application/json: schema: $ref: "#/components/schemas/AddProjectsToCollection" security: - ApiKeyAuth: [] /collections/remove_projects: post: tags: - Collections summary: Remove projects from collections description: Remove projects from collections operationId: removeProjectsFromCollections requestBody: $ref: "#/components/requestBodies/AddProjectsToCollection" responses: "200": description: successful operation security: - ApiKeyAuth: [] "/collections/user_project_access/{collectionId}": get: tags: - Collections summary: List users with project access in collection description: List of users who have access to projects within a collection operationId: UsersByCollectionProjectAccess parameters: - in: path name: collectionId required: true schema: type: integer responses: "200": description: successful operation security: - ApiKeyAuth: [] /collections/user_project_access: post: tags: - Collections summary: Add user project access to collection description: Grant user access to projects within a collection operationId: AddUserProjectAccessToCollection requestBody: $ref: "#/components/requestBodies/UserCollectionAccess" responses: "200": description: successful operation security: - ApiKeyAuth: [] /collections/remove_user_project_access: post: tags: - Collections summary: Remove user project access from collection description: Remove user access to projects within a collection operationId: RemoveUserProjectAccessFromCollection requestBody: $ref: "#/components/requestBodies/RemoveUserCollectionAccess" responses: "200": description: successful operation security: - ApiKeyAuth: [] /collections/template: post: tags: - Collections - Templates summary: Set template for collection description: Set template for all projects in a collection operationId: SetTemplateForCollection requestBody: content: application/json: schema: $ref: "#/components/schemas/TemplateForCollection" required: true responses: "200": description: successful operation security: - ApiKeyAuth: [] "/collections/user_acl/{collectionId}": get: tags: - Collections summary: List users with collection ACL access description: List of users who have ACL access to a collection itself operationId: UsersByCollectionACL parameters: - in: path name: collectionId required: true schema: type: integer responses: "200": description: successful operation security: - ApiKeyAuth: [] /collections/user_acl: post: tags: - Collections summary: Add user ACL access to collection description: Grant user ACL access to a collection itself operationId: AddUserACLToCollection requestBody: $ref: "#/components/requestBodies/UserCollectionAccess" responses: "200": description: successful operation security: - ApiKeyAuth: [] /collections/user_acl_update: post: tags: - Collections summary: Update user ACL permissions for collection description: Update user ACL permissions for a collection itself operationId: UpdateUserACLForCollection requestBody: $ref: "#/components/requestBodies/UserCollectionAccess" responses: "200": description: successful operation security: - ApiKeyAuth: [] /collections/user_acl_remove: post: tags: - Collections summary: Remove user ACL access from collection description: Remove user ACL access from a collection itself operationId: RemoveUserACLFromCollection requestBody: $ref: "#/components/requestBodies/RemoveUserCollectionAccess" responses: "200": description: successful operation security: - ApiKeyAuth: [] "/collections/user_acl_check/{collectionId}/{userId}": get: tags: - Collections summary: Check user ACL access to collection description: Check if a user has ACL access to a collection itself operationId: CheckUserACLForCollection parameters: - in: path name: collectionId required: true schema: type: integer - in: path name: userId required: true description: User ID to check schema: type: integer responses: "200": description: successful operation security: - ApiKeyAuth: [] "/resources/{projectId}": get: tags: - External resources summary: List resources description: List documentation (Reports, Questionnaires, Tables, etc.) for a project operationId: ListResources parameters: - in: path name: projectId required: true schema: type: integer responses: "200": description: successful operation content: application/json: schema: $ref: resource-schema.json security: - ApiKeyAuth: [] post: tags: - External resources summary: Create resource description: > Create a new resource for a project. This endpoint accepts multipart/form-data to allow file uploads along with resource metadata. **File Upload**: If the 'file' parameter is provided, the file will be uploaded and attached to the resource. **Filename/URL**: The 'filename' parameter (string) can be used to specify either a filename or a URL. This is separate from the file upload. operationId: CreateResource parameters: - in: path name: projectId required: true schema: type: integer requestBody: content: multipart/form-data: schema: type: object properties: dctype: description: Resource type type: string title: description: Resource title type: string author: type: string dcdate: type: string country: type: string language: type: string contributor: type: string publisher: type: string rights: type: string description: type: string abstract: type: string toc: type: string file: description: > File to upload and attach to this resource. Send as multipart/form-data with field name 'file'. If provided, the file will be uploaded and associated with the resource. The file can be any type (PDF, document, image, etc.). type: string format: binary filename: description: > Filename or URL for the resource. This can be either a filename string or a URL pointing to an external resource. This is separate from the 'file' parameter - use 'file' to upload a file, or 'filename' to specify a filename/URL. type: string overwrite: description: > When creating a resource, if another resource already uses the same stored filename for this project, set to `true` to replace that row instead of failing validation. Use `false` or omit to keep the duplicate-filename error. With `multipart/form-data`, send the literal strings `true` or `false` if your client cannot encode JSON booleans. type: boolean default: false required: - dctype - title required: true responses: "200": description: successful operation content: application/json: schema: $ref: resource-schema.json security: - ApiKeyAuth: [] "/resources/{projectId}/{resourceId}": post: tags: - External resources summary: Update resource description: > Update external resource for a project. This endpoint accepts multipart/form-data to allow file uploads along with resource metadata. **File Upload**: If the 'file' parameter is provided, the file will be uploaded and attached to the resource (replacing any existing file). **Filename/URL**: The 'filename' parameter (string) can be used to specify either a filename or a URL. This is separate from the file upload. operationId: UpdateResource parameters: - in: path name: projectId required: true schema: type: integer - in: path name: resourceId required: true schema: type: integer requestBody: content: multipart/form-data: schema: type: object properties: dctype: description: Resource type type: string title: description: Resource title type: string author: type: string dcdate: type: string country: type: string language: type: string contributor: type: string publisher: type: string rights: type: string description: type: string abstract: type: string toc: type: string file: description: > File to upload and attach to this resource. Send as multipart/form-data with field name 'file'. If provided, the file will be uploaded and associated with the resource (replacing any existing file). The file can be any type (PDF, document, image, etc.). type: string format: binary filename: description: > Filename or URL for the resource. This can be either a filename string or a URL pointing to an external resource. This is separate from the 'file' parameter - use 'file' to upload a file, or 'filename' to specify a filename/URL. type: string required: - dctype - title required: true responses: "200": description: successful operation content: application/json: schema: $ref: resource-schema.json security: - ApiKeyAuth: [] "/resources/write_json{projectId}": get: tags: - External resources summary: Generate JSON description: Generate JSON for external resources operationId: ResourcesWriteJSON parameters: - in: path name: projectId required: true schema: type: integer responses: "200": description: successful operation security: - ApiKeyAuth: [] "/resources/write_rdf{projectId}": get: tags: - External resources summary: Generate RDF description: Generate RDF for external resources operationId: ResourcesRdfJSON parameters: - in: path name: projectId required: true schema: type: integer responses: "200": description: successful operation security: - ApiKeyAuth: [] "/resources/rdf{projectId}": get: tags: - External resources summary: Download RDF description: Download RDF for external resources operationId: DownloadResourcesRdf parameters: - in: path name: projectId required: true schema: type: integer responses: "200": description: successful operation security: - ApiKeyAuth: [] "/resources/import/{projectId}": post: tags: - External resources summary: Import RDF or JSON description: Import external resources using RDF or JSON operationId: importResources parameters: - in: path name: projectId required: true schema: type: integer requestBody: content: application/x-www-form-urlencoded: schema: type: object properties: file: description: Upload RDF or JSON file type: string format: binary required: - file required: true responses: "200": description: successful operation content: application/json: schema: $ref: resource-schema.json security: - ApiKeyAuth: [] "/resources/delete/{projectId}/{resourceId}": post: tags: - External resources summary: Delete resource description: Delete external resource for a project operationId: deleteResource parameters: - in: path name: projectId required: true schema: type: integer - in: path name: resourceId required: true schema: type: integer responses: "200": description: successful operation security: - ApiKeyAuth: [] "/resources/generate_microdata/{projectId}": post: tags: - External resources summary: Generate microdata resource description: > Export project data files to the chosen format, copy the artifact into documentation/, and create a dat/micro external resource with optional data-file links. May take several minutes while FastAPI export jobs complete. operationId: generateMicrodataResource parameters: - in: path name: projectId required: true schema: type: integer requestBody: content: application/json: schema: type: object properties: export_format: type: string description: csv, dta, sav, xpt, or json export_version: type: string description: Stata version when export_format is dta (default 14) file_ids: type: array items: type: string description: Data file IDs (F1, F2, …); all files when omitted zip: type: boolean description: Bundle exports into one ZIP (default true) overwrite: type: boolean description: Replace existing generated resource for this format max_wait_seconds: type: integer description: Max seconds to wait per export job (default 900) required: - export_format responses: "200": description: Resource created, or already exists when overwrite is false security: - ApiKeyAuth: [] "/resources/regenerate/{projectId}/{resourceId}": post: tags: - External resources summary: Regenerate microdata resource description: > Re-export and update an existing generated dat/micro resource. Export format, version, and file selection default from existing link rows when omitted. operationId: regenerateMicrodataResource parameters: - in: path name: projectId required: true schema: type: integer - in: path name: resourceId required: true schema: type: integer requestBody: content: application/json: schema: type: object properties: export_format: type: string export_version: type: string file_ids: type: array items: type: string zip: type: boolean refresh_description: type: boolean max_wait_seconds: type: integer responses: "200": description: Resource regenerated security: - ApiKeyAuth: [] "/resources/microdata_status/{projectId}": get: tags: - External resources summary: Microdata publish status description: > Summary counts, per-resource staleness, and data-file link details for dat/micro external resources. operationId: microdataStatus parameters: - in: path name: projectId required: true schema: type: integer responses: "200": description: successful operation security: - ApiKeyAuth: [] "/resources/datafile_links/{projectId}/{resourceId}": get: tags: - External resources summary: List data file links description: List optional data-file links for a dat/micro resource operationId: listResourceDatafileLinks parameters: - in: path name: projectId required: true schema: type: integer - in: path name: resourceId required: true schema: type: integer responses: "200": description: successful operation security: - ApiKeyAuth: [] put: tags: - External resources summary: Replace data file links description: > Replace manual or associated links for a non-generated microdata resource. Generated resources must use regenerate instead. operationId: replaceResourceDatafileLinks parameters: - in: path name: projectId required: true schema: type: integer - in: path name: resourceId required: true schema: type: integer requestBody: content: application/json: schema: type: object properties: links: type: array items: type: object properties: file_id: type: string link_type: type: string description: manual or associated required: - file_id required: - links responses: "200": description: successful operation security: - ApiKeyAuth: [] post: tags: - External resources summary: Replace data file links (POST) description: Same as PUT; provided for clients that cannot send PUT requests operationId: replaceResourceDatafileLinksPost parameters: - in: path name: projectId required: true schema: type: integer - in: path name: resourceId required: true schema: type: integer requestBody: content: application/json: schema: type: object properties: links: type: array items: type: object properties: file_id: type: string link_type: type: string required: - file_id required: - links responses: "200": description: successful operation security: - ApiKeyAuth: [] /templates: get: tags: - Templates summary: List templates description: Get a list of all templates operationId: listTemplates responses: "200": description: successful operation security: - ApiKeyAuth: [] post: tags: - Templates summary: Create template description: Create a new template operationId: createTemplate requestBody: content: application/json: schema: $ref: template-schema.json required: true responses: "200": description: successful operation security: - ApiKeyAuth: [] "/templates/{uid}": get: tags: - Templates summary: Get template by UID description: Get template by UID operationId: getTemplate parameters: - in: path name: uid required: true schema: type: string responses: "200": description: successful operation security: - ApiKeyAuth: [] "/templates/duplicate/{uid}": post: tags: - Templates summary: Duplicate template description: Create duplicate template operationId: duplicateTemplate parameters: - in: path name: uid description: Template UID to create a duplicate required: true schema: type: string responses: "200": description: successful operation security: - ApiKeyAuth: [] "/templates/update/{uid}": post: tags: - Templates summary: Update template description: Update template operationId: updateTemplate parameters: - in: path name: uid description: Template UID to update required: true schema: type: string requestBody: content: application/json: schema: $ref: "#/components/schemas/Template" required: true responses: "200": description: successful operation security: - ApiKeyAuth: [] "/templates/delete/{uid}": post: tags: - Templates summary: Delete template description: Delete template operationId: deleteTemplate parameters: - in: path name: uid description: Template UID to delete required: true schema: type: string responses: "200": description: successful operation security: - ApiKeyAuth: [] "/templates/translation_keys/{uid}": get: tags: - Templates summary: Get template translation keys description: Get translation keys for a specific template. Returns all translatable text keys found in the template structure. operationId: getTemplateTranslationKeys parameters: - in: path name: uid description: Template UID required: true schema: type: string - in: query name: format description: Response format - 'full' for detailed array, 'compact' for key:value pairs schema: type: string enum: - full - compact default: full responses: "200": description: successful operation content: application/json: schema: type: object properties: status: type: string example: success translation_keys: type: array description: Array of translation keys (when format=full) items: type: object properties: key: type: string description: Translation key title: type: string description: Default title text prop_key: type: string description: Property key if different from main key translations: type: object description: Key-value pairs of translations (when format=compact) additionalProperties: type: string "400": description: Bad request - missing UID parameter or template not found content: application/json: schema: type: object properties: status: type: string example: failed message: type: string example: Missing parameter for `UID` security: - ApiKeyAuth: [] "/templates/revisions/{uid}": get: tags: - Templates summary: Get template revision history description: > Paginated edit history for a form template. Each entry may include a v1 change record (`version`, `scope`, `summary`, `patch`) describing template JSON changes. operationId: getTemplateRevisions parameters: - in: path name: uid description: Template UID required: true schema: type: string - in: query name: limit description: Page size (maximum 100) schema: type: integer default: 15 minimum: 1 maximum: 100 - in: query name: offset description: Number of entries to skip schema: type: integer default: 0 minimum: 0 responses: "200": description: successful operation content: application/json: schema: type: object properties: status: type: string example: success data: $ref: "#/components/schemas/TemplateRevisionHistoryResponse" "400": description: Bad request security: - ApiKeyAuth: [] "/editor/options/{id}": post: tags: - Templates - Project summary: Set project template description: Set project template operationId: setProjectTemplate parameters: - in: path name: id description: Project ID or IDNO required: true schema: type: string requestBody: $ref: "#/components/requestBodies/ProjectTemplate" responses: "200": description: successful operation security: - ApiKeyAuth: [] "/editor/options/{projectId}": post: tags: - Project summary: Change project IDNO description: Change project IDNO operationId: setProjectIDNO parameters: - in: path name: id description: Project ID or IDNO required: true schema: type: string requestBody: $ref: "#/components/requestBodies/ProjectTemplate" responses: "200": description: successful operation security: - ApiKeyAuth: [] /admin-metadata/templates: get: tags: - Admin metadata templates summary: List templates description: List all administrative metadata templates operationId: listAdminMetadataTemplates responses: "200": description: successful operation security: - ApiKeyAuth: [] "/admin-metadata/templates/{templateUid}": get: tags: - Admin metadata templates summary: Get single template description: Get single administrative metadata template operationId: singleAdminMetadataTemplate parameters: - in: path name: templateUid description: Admin metadata template UID required: true schema: type: string responses: "200": description: successful operation security: - ApiKeyAuth: [] "/admin-metadata/data/{projectId}/{templateUid}": get: tags: - Admin metadata summary: Get data description: Get admin metadata associated with a project operationId: getAdminMetadataData parameters: - in: path name: projectId description: Project ID or IDNO required: true schema: type: string - in: path name: templateUid description: Admin metadata template UID required: true schema: type: string responses: "200": description: successful operation security: - ApiKeyAuth: [] /admin-metadata/data_query: get: tags: - Admin metadata summary: Query admin metadata description: Query administrative metadata across projects. By default, returns all admin metadata for all projects and templates that the user has access to. To filter by project, template, date range or limit the number of results, use the query parameters. operationId: queryAdminMetadataData parameters: - in: query name: project_id description: (optional) Project ID or IDNO required: false schema: type: string - in: query name: template description: (optional) Admin metadata template UID. For multiple templates, separate with comma required: false schema: type: string - in: query name: limit description: (optional) Limit number of results. Default is 50 required: false schema: type: integer - in: query name: offset description: (optional) Offset number of results. Default is 0 required: false schema: type: integer - in: query name: date_from description: "(optional) Filter by date from (format: YYYY-MM-DD). Filters on the 'changed' field. Records with changed date >= date_from will be returned." required: false schema: type: string format: date - in: query name: date_to description: "(optional) Filter by date to (format: YYYY-MM-DD). Filters on the 'changed' field. Records with changed date <= date_to will be returned. The entire end date is included." required: false schema: type: string format: date responses: "200": description: successful operation security: - ApiKeyAuth: [] /admin-metadata/data/: post: tags: - Admin metadata summary: Add/update data description: Add or update admin metadata (data) for a project operationId: createAdminMetadataData requestBody: content: application/json: schema: $ref: "#/components/schemas/CreateAdminMetadataData" required: true responses: "200": description: successful operation security: - ApiKeyAuth: [] /admin-metadata/data_patch/: post: tags: - Admin metadata summary: Partial update (patch) description: Apply JSON patch operations to partially update admin metadata. operationId: patchAdminMetadataData requestBody: content: application/json: schema: $ref: "#/components/schemas/PatchAdminMetadataData" required: true responses: "200": description: successful operation "400": description: Bad request - Invalid patch operations or missing required fields security: - ApiKeyAuth: [] /admin-metadata/data_remove/: post: tags: - Admin metadata summary: Delete description: Delete admin metadata for a project operationId: deleteAdminMetadataData requestBody: content: application/json: schema: $ref: "#/components/schemas/RemoveAdminMetadataData" required: true responses: "200": description: successful operation security: - ApiKeyAuth: [] "/admin-metadata/edit_history/{projectId}/{templateUid}": get: tags: - Admin metadata summary: Get admin metadata edit history description: > Paginated audit log of admin metadata changes for a project and admin metadata template. Each entry may include a v1 change record with `version`, `scope`, `summary`, and `patch`. operationId: getAdminMetadataHistory parameters: - in: path name: projectId description: Project ID or IDNO required: true schema: type: string - in: path name: templateUid description: Admin metadata template UID required: true schema: type: string - in: query name: limit description: Page size (maximum 100) schema: type: integer default: 15 minimum: 1 maximum: 100 - in: query name: offset description: Number of entries to skip schema: type: integer default: 0 minimum: 0 responses: "200": description: successful operation content: application/json: schema: $ref: "#/components/schemas/AdminMetadataHistoryResponse" "400": description: Bad request security: - ApiKeyAuth: [] /publish/catalog_connections: get: tags: - Publish projects summary: List catalog connections for publishing description: Get all catalog connections configured by the current user for publishing projects to NADA catalogs operationId: listPublishCatalogConnections responses: "200": description: successful operation content: application/json: schema: type: object properties: connections: type: array items: $ref: "#/components/schemas/CatalogConnection" "400": description: Bad request security: - ApiKeyAuth: [] post: tags: - Publish projects summary: Create catalog connection for publishing description: Create a new catalog connection for publishing projects to NADA catalogs operationId: createPublishCatalogConnection requestBody: $ref: "#/components/requestBodies/CatalogConnection" responses: "200": description: successful operation "400": description: Bad request security: - ApiKeyAuth: [] "/publish/catalog_info/{sid}/{catalog_connection_id}": get: tags: - Publish projects summary: Get NADA catalog info for publish form description: > Fetches data used to populate the publish UI: study record from the target NADA catalog (if the study IDNO exists), list of collections, allowed data-access codes, and collections already linked to the study. Calls the configured catalog base URL with the stored API key — e.g. `GET .../index.php/api/collections`, `GET .../index.php/api/catalog/data_access_codes`, `GET .../api/datasets/{idno}`, `GET .../api/datasets/collections/{idno}`. operationId: getNadaCatalogInfoForPublish parameters: - in: path name: sid description: Project ID (internal Metadata Editor project id) required: true schema: type: string - in: path name: catalog_connection_id description: Catalog connection ID (from list catalog connections) required: true schema: type: integer responses: "200": description: Catalog information for the publish form content: application/json: schema: $ref: "#/components/schemas/NadaCatalogInfoResponse" "400": description: Bad request — user not logged in, missing parameters, or project not found security: - ApiKeyAuth: [] "/publish/indicator/{sid}/{catalog_connection_id}": post: tags: - Publish projects summary: Publish indicator DSD and/or data to NADA description: > For indicator/timeseries projects only. Optionally publishes the bound data structure definition (DSD) via NADA `POST .../api/admin/data_structures/import_json`, and/or exports published DuckDB timeseries rows to CSV, resumable-uploads to NADA, and imports observations via `POST .../api/admin/timeseries/data/{study_idno}/import` (or `.../data/import`) with `upload_id`. DSD publish skips when the structure already exists on NADA unless `dsd_overwrite` is true. Indicator data always replaces existing observations for the study on NADA. operationId: publishIndicatorExtrasToNada parameters: - in: path name: sid description: Project ID (internal Metadata Editor project id) required: true schema: type: string - in: path name: catalog_connection_id description: Catalog connection ID required: true schema: type: integer requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/IndicatorPublishOptions" responses: "200": description: DSD and/or data publish result content: application/json: schema: $ref: "#/components/schemas/IndicatorPublishResponse" "400": description: Bad request — not an indicator project, missing binding, or NADA error security: - ApiKeyAuth: [] "/publish/nada_upload_limits/{catalog_connection_id}": get: tags: - Publish projects summary: NADA resumable upload limits (proxy) operationId: getNadaUploadLimitsForPublish parameters: - in: path name: catalog_connection_id required: true schema: type: integer - in: query name: project_id required: true schema: type: string responses: "200": description: Chunk size limits from target NADA catalog security: - ApiKeyAuth: [] "/publish/nada_upload_init/{catalog_connection_id}": post: tags: - Publish projects summary: Initialize NADA resumable upload (proxy) operationId: initNadaUploadForPublish parameters: - in: path name: catalog_connection_id required: true schema: type: integer requestBody: required: true content: application/json: schema: type: object required: [project_id, filename, total_size, total_chunks, chunk_size] properties: project_id: type: string filename: type: string total_size: type: integer total_chunks: type: integer chunk_size: type: integer responses: "200": description: NADA upload_id for subsequent chunk posts security: - ApiKeyAuth: [] "/publish/nada_upload_chunk/{catalog_connection_id}/{upload_id}": post: tags: - Publish projects summary: Upload one chunk to NADA (proxy) operationId: uploadNadaChunkForPublish parameters: - in: path name: catalog_connection_id required: true schema: type: integer - in: path name: upload_id required: true schema: type: string - in: query name: project_id required: true schema: type: string requestBody: required: true content: application/octet-stream: schema: type: string format: binary responses: "200": description: Chunk accepted security: - ApiKeyAuth: [] "/publish/nada_upload_status/{catalog_connection_id}/{upload_id}": get: tags: - Publish projects summary: NADA resumable upload status (proxy) operationId: getNadaUploadStatusForPublish parameters: - in: path name: catalog_connection_id required: true schema: type: integer - in: path name: upload_id required: true schema: type: string - in: query name: project_id required: true schema: type: string responses: "200": description: Upload status from NADA security: - ApiKeyAuth: [] "/publish/{sid}/{catalog_connection_id}": post: tags: - Publish projects summary: Publish project metadata description: > Publishes project metadata to a NADA catalog. The server loads the exported project JSON (generated for the project), then **merges** each property from the request body into that object as top-level keys. The combined JSON is sent to the catalog as `POST {catalog_url}/index.php/api/datasets/create/{type}` with header `x-api-key`, where `{type}` is derived from the project (e.g. `survey`, `timeseries`, `timeseries-db`). Typical merge fields from the Metadata Editor UI are `overwrite`, `published`, `access_policy`, `data_remote_url`, and `repositoryid` (see schema). Omit the body or send `{}` to publish without overriding those fields. operationId: publishProjectMetadata parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: catalog_connection_id description: Catalog connection ID required: true schema: type: integer requestBody: required: false content: application/json: schema: $ref: "#/components/schemas/PublishOptions" examples: full: summary: Typical UI payload value: overwrite: "yes" published: 1 access_policy: licensed data_remote_url: "" repositoryid: MY_COLLECTION description: > NADA publish options merged into the project metadata JSON before POST to the catalog. All properties are optional; only supplied keys are merged. responses: "200": description: Project metadata published successfully (response shape follows NADA API) "400": description: Bad request - project not found, catalog connection not found, or publishing failed security: - ApiKeyAuth: [] "/publish/thumbnail/{sid}/{catalog_connection_id}": post: tags: - Publish projects summary: Publish project thumbnail description: Publish project thumbnail image to a NADA catalog operationId: publishProjectThumbnail parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: catalog_connection_id description: Catalog connection ID required: true schema: type: integer requestBody: required: false content: application/json: schema: type: object description: Optional JSON body; Metadata Editor sends `{}` responses: "200": description: Thumbnail published successfully content: application/json: schema: type: object properties: status: type: string example: success result: type: object "400": description: Bad request - project not found, thumbnail not found, or publishing failed security: - ApiKeyAuth: [] "/publish/external_resource/{sid}/{catalog_connection_id}": post: tags: - Publish projects summary: Publish single external resource description: > Publish a single external resource (documentation file) to a NADA catalog. `catalog_id` in the body must match the catalog connection used for publishing. The optional trailing path segment matches the client URL pattern; the catalog is taken from the JSON body (`catalog_id`). operationId: publishSingleExternalResource parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: catalog_connection_id description: Catalog connection ID (same as `catalog_id` in body; echoed in URL by clients) required: true schema: type: integer requestBody: content: application/json: schema: type: object required: - resource_id - catalog_id properties: resource_id: type: integer description: Resource ID to publish catalog_id: type: integer description: Catalog connection ID (must match path `catalog_connection_id` when both are used) sid: type: string description: Project ID (optional; echoed by some clients; path `sid` is authoritative) overwrite: type: string enum: - yes - no default: no description: > Sent to NADA on the resource payload as `overwrite`. When `yes`, replaces an existing resource with the same identity in the catalog. required: true responses: "200": description: Resource published successfully content: application/json: schema: type: object properties: resource: type: object description: Resource metadata response resource_upload: type: object description: Resource file upload response (if file was uploaded) "400": description: Bad request - missing parameters or publishing failed security: - ApiKeyAuth: [] "/publish/external_resources/{sid}/{connection_id}": post: tags: - Publish projects summary: Publish all external resources description: > Publishes every external resource for the project to NADA. For each resource, metadata is POSTed to `{catalog}/index.php/api/resources/{study_idno}` with `overwrite` set to `yes`. If the resource has a stored file (`filename` is set and not an external URL), the file is then uploaded to `{catalog}/index.php/api/datasets/{study_idno}/files`, matching the single-resource publish behavior. Request body JSON (if any) is accepted but not applied. operationId: publishAllExternalResources parameters: - in: path name: sid description: Project ID or IDNO required: true schema: type: string - in: path name: connection_id description: Catalog connection ID required: true schema: type: integer requestBody: required: false content: application/json: schema: type: object description: Optional; unused by the server today responses: "200": description: Resources published successfully content: application/json: schema: type: array items: type: object properties: resource: type: object description: NADA response for the resource metadata POST resource_upload: type: object description: NADA response for the file upload (only when a local file was attached) "400": description: Bad request - project not found or publishing failed security: - ApiKeyAuth: [] "/versions/{id}": get: tags: - Projects summary: Get project versions description: Get a list of versions for a project operationId: getProjectVersions parameters: - in: path name: id description: Project ID or IDNO required: true schema: type: string - name: version in: query title: Version number description: Get project by specific version number (e.g. 1.0.0) required: false schema: type: string responses: "200": description: successful operation security: - ApiKeyAuth: [] /versions/create: post: tags: - Projects summary: Create project version description: Create a new version for a project operationId: createProjectVersion requestBody: content: application/json: schema: $ref: "#/components/schemas/CreateProjectVersion" required: true responses: "200": description: successful operation security: - ApiKeyAuth: [] /versions/delete: post: tags: - Projects summary: Delete project version description: Delete a version for a project operationId: deleteProjectVersion requestBody: content: application/json: schema: $ref: "#/components/schemas/DeleteProjectVersion" required: true responses: "200": description: successful operation security: - ApiKeyAuth: [] /versions/delete_by_id: post: tags: - Projects summary: Delete project version by ID description: Delete a version for a project by ID operationId: deleteProjectVersionById requestBody: content: application/json: schema: $ref: "#/components/schemas/DeleteProjectVersionById" required: true responses: "200": description: successful operation security: - ApiKeyAuth: [] /catalog-connections: get: tags: - Catalog connections summary: List catalog connections description: List all catalog connections operationId: listCatalogConnections responses: "200": description: successful operation post: tags: - Catalog connections summary: Create catalog connection description: Create a new catalog connection operationId: createCatalogConnection requestBody: $ref: "#/components/requestBodies/CatalogConnection" responses: "200": description: successful operation security: - ApiKeyAuth: [] "/catalog-connections/{id}": get: tags: - Catalog connections summary: Get catalog connection description: Get a catalog connection operationId: getCatalogConnection parameters: - in: path name: id description: Catalog connection ID required: true schema: type: integer responses: "200": description: successful operation security: - ApiKeyAuth: [] /catalog-connections/delete: post: tags: - Catalog connections summary: Delete catalog connection description: Delete a catalog connection operationId: deleteCatalogConnection requestBody: content: application/json: schema: $ref: "#/components/schemas/CatalogConnectionDelete" required: true responses: "200": description: successful operation security: - ApiKeyAuth: [] /catalog-connections/update: post: tags: - Catalog connections summary: Update catalog connection description: Update a catalog connection operationId: updateCatalogConnection requestBody: $ref: "#/components/requestBodies/CatalogConnection" responses: "200": description: successful operation # ───────────────────────────────────────────────────────────────────────── # Codelists (global catalogue) # ───────────────────────────────────────────────────────────────────────── /codelists: get: tags: - Codelists summary: List codelists description: >- List global codelists. Default: one row per family (collapsed). Use `flat=1` for all version rows. Requires `codelist:browse` (registry view) permission. operationId: codelistsList parameters: - name: flat in: query schema: type: boolean description: When true, return one row per version instead of collapsed families. - name: collapsed in: query schema: type: boolean description: '`1` forces collapsed; `0` forces flat (overrides default).' - name: page in: query schema: type: integer minimum: 1 description: 1-based page number (max 200 per page). - name: per_page in: query schema: type: integer minimum: 1 maximum: 200 default: 50 - name: search in: query schema: type: string - name: q in: query schema: type: string description: Alias for `search`. - name: agency in: query schema: type: string - name: status in: query schema: $ref: '#/components/schemas/CodelistStatusCode' - name: exclude_archived in: query schema: type: boolean - name: with_counts in: query schema: type: boolean default: true description: Include `item_count` and `dsd_component_count` when true (default). - name: offset in: query schema: type: integer description: Legacy pagination offset (used when `page` is omitted). - name: limit in: query schema: type: integer description: Legacy page size (used when `page` is omitted). responses: '200': description: Codelist catalogue rows content: application/json: schema: $ref: '#/components/schemas/CodelistListResponse' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' '403': description: Registry access denied content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' post: tags: - Codelists summary: Create codelist description: Create a new global codelist header. Requires `codelist:edit`. operationId: codelistsCreate requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CodelistCreateRequest' responses: '200': description: Codelist created content: application/json: schema: $ref: '#/components/schemas/CodelistCreateResponse' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/versions/{name}": get: tags: - Codelists summary: List versions for a codelist family operationId: codelistsVersions parameters: - name: name in: path required: true schema: type: string description: SDMX maintainable id (codelist name). - name: agency in: query schema: type: string - name: with_counts in: query schema: type: boolean default: true responses: '200': description: Version rows content: application/json: schema: $ref: '#/components/schemas/CodelistVersionsResponse' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/single/{id}": get: tags: - Codelists summary: Get codelist by id operationId: codelistsSingle parameters: - name: id in: path required: true schema: type: integer responses: '200': description: Codelist row content: application/json: schema: $ref: '#/components/schemas/CodelistSingleResponse' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/lookup_by_identity": get: tags: - Codelists summary: Get codelist by SDMX identity (query params) description: >- Resolve by `agency`, `name`, and optional `version` query parameters (preferred when identity values contain special characters). operationId: codelistsLookupByIdentity parameters: - name: agency in: query required: true schema: type: string - name: name in: query required: true schema: type: string - name: version in: query schema: type: string description: Optional; empty string matches blank version in the database. responses: '200': description: Codelist row content: application/json: schema: $ref: '#/components/schemas/CodelistSingleResponse' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/by-identity/{agency}/{name}/{version}": get: tags: - Codelists summary: Get codelist by SDMX identity (path) operationId: codelistsByIdentity parameters: - name: agency in: path required: true schema: type: string - name: name in: path required: true schema: type: string - name: version in: path required: true schema: type: string description: May be empty for blank DB version. responses: '200': description: Codelist row content: application/json: schema: $ref: '#/components/schemas/CodelistSingleResponse' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/update/{id}": post: tags: - Codelists summary: Update codelist description: >- Update catalogue metadata (not agency/name/version identity). Requires `codelist:edit`. operationId: codelistsUpdate parameters: - name: id in: path required: true schema: type: integer requestBody: required: true content: application/json: schema: type: object additionalProperties: true responses: '200': description: Updated content: application/json: schema: $ref: '#/components/schemas/CodelistMutationResponse' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/delete/{id}": post: tags: - Codelists summary: Delete codelist description: Requires `codelist:delete`. Locked or archived codelists cannot be deleted. operationId: codelistsDelete parameters: - name: id in: path required: true schema: type: integer responses: '200': description: Deleted content: application/json: schema: $ref: '#/components/schemas/CodelistMutationResponse' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/codes/{id}": get: tags: - Codelists summary: List codes in a codelist operationId: codelistsCodesList parameters: - name: id in: path required: true schema: type: integer description: Codelist id - name: language in: query schema: type: string - name: search in: query schema: type: string - name: offset in: query schema: type: integer default: 0 - name: limit in: query schema: type: integer default: 50 description: Pass `0` to return all codes (no limit). - name: compact in: query schema: type: boolean description: When true, flatten labels to code/label/description per row. responses: '200': description: Code rows content: application/json: schema: $ref: '#/components/schemas/CodelistCodesResponse' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/import_json": post: tags: - Codelists summary: Import codelist JSON description: >- Import one codelist from NADA-compatible JSON (body or multipart `file`). Requires `codelist:import`. Supports `dry_run` and `replace`/`overwrite` on the JSON body or query string. operationId: codelistsImportJson parameters: - name: dry_run in: query schema: type: boolean - name: replace in: query schema: type: boolean requestBody: content: application/json: schema: type: object additionalProperties: true multipart/form-data: schema: type: object properties: file: type: string format: binary responses: '200': description: Import result content: application/json: schema: $ref: '#/components/schemas/CodelistImportResponse' '400': description: Validation or import failed content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/import_sdmx": post: tags: - Codelists summary: Import codelists from SDMX XML description: >- Import from raw XML body, multipart `file`, or JSON `{"url":"https://..."}`. Requires `codelist:import`. operationId: codelistsImportSdmx parameters: - name: dry_run in: query schema: type: boolean - name: replace in: query schema: type: boolean requestBody: content: multipart/form-data: schema: type: object properties: file: type: string format: binary application/json: schema: type: object properties: url: type: string format: uri application/xml: schema: type: string text/xml: schema: type: string responses: '200': description: Import summary content: application/json: schema: type: object additionalProperties: true '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/export_json/{id}": get: tags: - Codelists summary: Export codelist JSON operationId: codelistsExportJson parameters: - name: id in: path required: true schema: type: integer - name: download in: query schema: type: boolean default: true responses: '200': description: JSON document or attachment '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/export_csv/{id}": get: tags: - Codelists summary: Export codelist items CSV description: >- All items as UTF-8 CSV with BOM (Excel-compatible). Columns: sort, parent_code, language, code, label, description. operationId: codelistsExportCsv parameters: - name: id in: path required: true schema: type: integer - name: download in: query schema: type: boolean default: true responses: '200': description: CSV attachment or JSON wrapper with csv field '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/import_csv/{id}": post: tags: - Codelists summary: Import codelist items from CSV description: >- Requires `codelist:edit`. Replaces all existing items when replace=1 (default). Multipart file field or raw CSV body. dry_run=1 validates without saving. operationId: codelistsImportCsv parameters: - name: id in: path required: true schema: type: integer - name: dry_run in: query schema: type: boolean default: false - name: replace in: query schema: type: boolean default: true requestBody: content: multipart/form-data: schema: type: object properties: file: type: string format: binary text/csv: schema: type: string responses: '200': description: Import result content: application/json: schema: type: object properties: status: type: string dry_run: type: boolean codes_imported: type: integer codes_count: type: integer rows_parsed: type: integer warnings: type: array items: type: string '400': description: Validation or import failure content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/codelists/export_sdmx/{id}": get: tags: - Codelists summary: Export codelist SDMX XML operationId: codelistsExportSdmx parameters: - name: id in: path required: true schema: type: integer - name: version in: query schema: type: string enum: ['2.1', '3.0'] default: '2.1' responses: '200': description: SDMX-ML structure message (application/xml) '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' # ───────────────────────────────────────────────────────────────────────── # Data structures (global DSD catalogue) # ───────────────────────────────────────────────────────────────────────── /data_structures: get: tags: - Data Structures summary: List data structures description: List global DSDs. Supports collapsed or flat list and optional pagination. operationId: dataStructuresList parameters: - name: flat in: query schema: type: boolean description: When true, return one row per version. - name: page in: query schema: type: integer minimum: 1 description: 1-based page number. When provided, returns paginated payload. - name: per_page in: query schema: type: integer minimum: 1 maximum: 200 default: 50 - name: search in: query schema: type: string description: Search across title/name/agency/idno/version/description/notes. - name: q in: query schema: type: string description: Alias for `search`. - name: status in: query description: Exact status filter (`DataStructureStatusCode`). schema: $ref: '#/components/schemas/DataStructureStatusCode' responses: '200': description: Successful operation '400': description: Bad request /data_structures/single/{id}: get: tags: - Data Structures summary: Get data structure by id operationId: dataStructuresSingle parameters: - name: id in: path required: true schema: type: integer - name: with_components in: query schema: type: boolean description: When true, include components array. responses: '200': description: Successful operation '400': description: Bad request /data_structures/lookup/{segment}: get: tags: - Data Structures summary: Get data structure by id or idno operationId: dataStructuresLookup parameters: - name: segment in: path required: true schema: type: string - name: with_components in: query schema: type: boolean responses: '200': description: Successful operation '400': description: Bad request /data_structures/by_identity: get: tags: - Data Structures summary: Get data structure by SDMX identity operationId: dataStructuresByIdentity parameters: - name: agency in: query required: true schema: type: string - name: name in: query required: true schema: type: string - name: version in: query schema: type: string responses: '200': description: Successful operation '400': description: Bad request /data_structures/validate/{id}: get: tags: - Data Structures summary: Validate persisted data structure operationId: dataStructuresValidate parameters: - name: id in: path required: true schema: type: integer responses: '200': description: Validation report '400': description: Bad request /data_structures/export/{segment}: get: tags: - Data Structures summary: Export data structure JSON description: >- Returns import-ready interchange JSON per `data-structure-schema.json`: `data_structure` includes nested `components[]`; dimension/geography components embed inline `codelist` objects with `items` (not `codelist_reference` only). Suitable for `POST .../import_json` on this editor or NADA without a separate codelist export step. operationId: dataStructuresExport parameters: - name: segment in: path required: true schema: type: string description: Numeric id or catalogue idno. - name: download in: query schema: type: boolean default: true description: When true (default), respond as attachment download. responses: '200': description: Export payload or file download '400': description: Bad request /data_structures/versions/{segment}: get: tags: - Data Structures summary: List versions for a data structure family operationId: dataStructuresVersions parameters: - name: segment in: path required: true schema: type: string responses: '200': description: Successful operation '400': description: Bad request /data_structures/projects/{segment}: get: tags: - Data Structures summary: List projects linked to a data structure operationId: dataStructuresProjects parameters: - name: segment in: path required: true schema: type: string - name: page in: query schema: type: integer minimum: 1 - name: per_page in: query schema: type: integer minimum: 1 maximum: 200 responses: '200': description: Successful operation '400': description: Bad request /data_structures/create: post: tags: - Data Structures summary: Create data structure description: >- Create a global DSD header row (components added separately or via import_json). Request body matches `data-structure-schema.json`. operationId: dataStructuresCreate requestBody: required: true content: application/json: schema: $ref: 'data-structure-schema.json' responses: '200': description: Data structure created '400': description: Bad request /data_structures/update/{id}: post: tags: - Data Structures summary: Update data structure operationId: dataStructuresUpdate parameters: - name: id in: path required: true schema: type: integer requestBody: required: true content: application/json: schema: type: object additionalProperties: true responses: '200': description: Data structure updated '400': description: Bad request /data_structures/import_json: post: tags: - Data Structures summary: Import data structure JSON description: >- Import global DSD, components and codelists from JSON. Body matches `data-structure-schema.json`: root `data_structure` (identity + `components`), optional boolean `overwrite` and `dry_run` on the same JSON object (no query flags). operationId: dataStructuresImportJson requestBody: required: true content: application/json: schema: $ref: 'data-structure-schema.json' responses: '200': description: Validation/dry-run succeeded or import completed '400': description: Validation failed or bad request /data_structures/import_components_csv/{id}: post: tags: - Data Structures summary: Import components from CSV mapping description: >- Add components to an existing draft data structure using a CSV file and column mapping. Multipart form with `file` (CSV) and `payload` (JSON string), or JSON body with `upload_id` (completed resumable upload) plus mapping fields. Payload shape: `{ delimiter, dry_run?, overwrite?, components: [{ name, label, column_type, csv_column, codelist?: { mode: global|from_csv, ... } }] }`. Codelists created from CSV use maintainable id `CL_{component_name}` under the structure agency. operationId: dataStructuresImportComponentsCsv parameters: - name: id in: path required: true schema: type: integer requestBody: required: true content: multipart/form-data: schema: type: object required: [file, payload] properties: file: type: string format: binary payload: type: string description: JSON string with delimiter and components array application/json: schema: type: object required: [components] properties: upload_id: type: string delimiter: type: string dry_run: type: boolean overwrite: type: boolean components: type: array items: type: object additionalProperties: true responses: '200': description: Import or dry-run summary '400': description: Validation failed or bad request /data_structures/import_sdmx: post: tags: - Data Structures summary: Import data structure from SDMX XML description: Import SDMX-ML structure XML from multipart `file` or XML body. operationId: dataStructuresImportSdmx parameters: - name: overwrite_codelists in: query schema: type: boolean - name: dsd_id in: query schema: type: string description: Optional DataStructure @id selector when multiple are present in XML. requestBody: content: multipart/form-data: schema: type: object required: [file] properties: file: type: string format: binary overwrite_codelists: type: string dsd_id: type: string application/xml: schema: type: string text/xml: schema: type: string responses: '201': description: Import completed '400': description: Bad request /data_structures/components: get: tags: - Data Structures summary: Search data structure components across all DSDs description: | Paginated catalogue of components with parent DSD context. Requires at least one of `search` (min 2 characters), `name`, or `structure_id`. operationId: dataStructuresComponentsSearch parameters: - name: search in: query schema: type: string description: Match component name, label, description, or parent DSD metadata. - name: q in: query schema: type: string description: Alias for `search`. - name: name in: query schema: type: string description: Prefix match on component name (e.g. REF_AREA). - name: column_type in: query schema: type: string enum: - dimension - time_period - measure - attribute - indicator_id - indicator_name - annotation - geography - observation_value - periodicity - name: agency in: query schema: type: string description: Filter by parent DSD agency. - name: structure_id in: query schema: type: integer description: Limit results to one DSD. - name: exclude_structure_id in: query schema: type: integer description: Exclude components from a DSD (e.g. current draft when copying). - name: status in: query schema: $ref: '#/components/schemas/DataStructureStatusCode' description: Filter by parent DSD status. - name: has_codelist in: query schema: type: boolean description: When true, only components with a linked codelist. - name: page in: query schema: type: integer minimum: 1 default: 1 - name: per_page in: query schema: type: integer minimum: 1 maximum: 200 default: 50 - name: order_by in: query schema: type: string enum: [name, structure_title, updated] default: name - name: order_dir in: query schema: type: string enum: [ASC, DESC] default: ASC responses: '200': description: Paginated component search results '400': description: Bad request /data_structures/components/{structure_id}: post: tags: - Data Structures summary: Create data structure component operationId: dataStructuresComponentCreate parameters: - name: structure_id in: path required: true schema: type: integer requestBody: required: true content: application/json: schema: type: object additionalProperties: true responses: '200': description: Component created '400': description: Bad request /data_structures/component_update/{id}: post: tags: - Data Structures summary: Update data structure component operationId: dataStructuresComponentUpdate parameters: - name: id in: path required: true schema: type: integer requestBody: required: true content: application/json: schema: type: object additionalProperties: true responses: '200': description: Component updated '400': description: Bad request /data_structures/component_delete/{id}: post: tags: - Data Structures summary: Delete data structure component operationId: dataStructuresComponentDelete parameters: - name: id in: path required: true schema: type: integer responses: '200': description: Component deleted '400': description: Bad request /data_structures/duplicate/{id}: post: tags: - Data Structures summary: Duplicate data structure operationId: dataStructuresDuplicate parameters: - name: id in: path required: true schema: type: integer requestBody: content: application/json: schema: type: object properties: name: type: string agency: type: string version: type: string responses: '200': description: Duplicate created '400': description: Bad request /data_structures/delete/{id}: post: tags: - Data Structures summary: Delete data structure operationId: dataStructuresDelete parameters: - name: id in: path required: true schema: type: integer responses: '200': description: Deleted '400': description: Bad request /data_structures/batch_delete: post: tags: - Data Structures summary: Batch delete data structures operationId: dataStructuresBatchDelete requestBody: required: true content: application/json: schema: type: object required: [ids] properties: ids: type: array items: type: integer responses: '200': description: Batch delete result '400': description: Bad request # ───────────────────────────────────────────────────────────────────────── # Indicator DSD (project binding and data) # ───────────────────────────────────────────────────────────────────────── "/indicator_dsd/{sid}": get: tags: - Indicator DSD summary: List DSD columns for a project description: >- Returns resolved DSD columns for the project. When bound to a global catalogue DSD, columns are read from the registry (read-only). Use `resolve_codelists=1` to expand linked global codelists into each column. operationId: indicatorDsdList parameters: - name: sid in: path required: true schema: type: string description: Project id or idno - name: detailed in: query schema: type: integer enum: [0, 1] - name: resolve_codelists in: query schema: type: integer enum: [0, 1] - name: offset in: query schema: type: integer - name: limit in: query schema: type: integer responses: '200': description: Column list '400': description: Bad request "/indicator_dsd/single/{sid}/{id}": get: tags: - Indicator DSD summary: Get single DSD column operationId: indicatorDsdSingle parameters: - name: sid in: path required: true schema: type: string - name: id in: path required: true schema: type: integer responses: '200': description: Column detail '400': description: Bad request "/indicator_dsd/validate/{sid}": get: tags: - Indicator DSD summary: Validate project DSD structure and data description: >- Validates bound global DSD structure first. Data checks (column presence, codelist allow-lists, observation-key uniqueness) run only when structure is valid and published timeseries data exists in DuckDB. Always returns HTTP 200 with a report when the project exists (use `valid` and nested blocks, not only HTTP status). operationId: indicatorDsdValidate parameters: - name: sid in: path required: true schema: type: string description: Project numeric id or idno responses: '200': description: Validation report (HTTP 200 even when validation fails) content: application/json: schema: $ref: '#/components/schemas/IndicatorDsdValidateResponse' '400': description: Bad request (e.g. project not found) content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/indicator_dsd/binding/{sid}": get: tags: - Indicator DSD summary: Get project DSD binding context description: >- Binding state, metadata `data_structure_reference`, global structure header, import readiness (`import_ready`, `import_blocked_reasons`), and structure validation summary. Use before data upload to confirm `indicator_id_value` and `implied_freq_code` are set. operationId: indicatorDsdBinding parameters: - name: sid in: path required: true schema: type: string description: Project numeric id or idno responses: '200': description: Binding context content: application/json: schema: $ref: '#/components/schemas/IndicatorDsdBindingResponse' '400': description: Bad request content: application/json: schema: $ref: '#/components/schemas/ApiStatusFailed' "/indicator_dsd/bind_global/{sid}": post: tags: - Indicator DSD summary: Bind global catalogue DSD to project description: >- Attach a registry DSD. Supply `data_structure_id` or `data_structure_reference` (see `DataStructureReference`). Optionally set `indicator_id_value` for data import. operationId: indicatorDsdBindGlobal parameters: - name: sid in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/IndicatorDsdBindRequest' responses: '200': description: Bound '400': description: Bad request "/indicator_dsd/update_binding/{sid}": post: tags: - Indicator DSD summary: Update project DSD binding fields operationId: indicatorDsdUpdateBinding parameters: - name: sid in: path required: true schema: type: string requestBody: required: true content: application/json: schema: type: object properties: indicator_id_value: type: string implied_freq_code: type: string description: SDMX FREQ code when structure has no periodicity column responses: '200': description: Updated '400': description: Bad request "/indicator_dsd/unbind/{sid}": post: tags: - Indicator DSD summary: Detach global DSD from project description: Removes binding, clears metadata reference, and drops published timeseries data. operationId: indicatorDsdUnbind parameters: - name: sid in: path required: true schema: type: string responses: '200': description: Unbound '400': description: Bad request "/indicator_dsd/reset/{sid}": post: tags: - Indicator DSD summary: Reset published indicator data description: Drops the DuckDB timeseries table for the project. operationId: indicatorDsdReset parameters: - name: sid in: path required: true schema: type: string responses: '200': description: Reset result '400': description: Bad request "/indicator_dsd/data_upload_prepare/{sid}": post: tags: - Indicator DSD summary: Prepare indicator data upload description: >- Upload a CSV (or reference a completed resumable `upload_id`), validate required DSD column headers, stage the file on the project, and return distinct values in the indicator_id column. Does not require `indicator_id_value` or `implied_freq_code` (those are enforced on `data_upload_import`). Provide **either** `file` **or** `upload_id`, not both. operationId: indicatorDsdDataUploadPrepare parameters: - name: sid in: path required: true schema: type: string description: Project numeric id or idno requestBody: required: true content: multipart/form-data: schema: type: object properties: file: type: string format: binary description: CSV file to stage (mutually exclusive with upload_id) upload_id: type: string description: >- Completed resumable upload session id from `POST /upload/{sid}` (mutually exclusive with file) delimiter: type: string maxLength: 1 default: "," description: CSV field delimiter (single character) keep_extra_csv_columns: type: string description: >- When `true`/`1`/`yes`, extra CSV columns beyond the DSD are kept on import description: Supply `file` or `upload_id` (not both). responses: '200': description: Headers valid; CSV staged for import content: application/json: schema: $ref: '#/components/schemas/IndicatorDsdDataUploadPrepareResponse' '400': description: Header validation failed or request error content: application/json: schema: oneOf: - $ref: '#/components/schemas/IndicatorDsdDataUploadPrepareHeaderError' - $ref: '#/components/schemas/ApiStatusFailed' "/indicator_dsd/data_upload_import/{sid}": post: tags: - Indicator DSD summary: Import prepared indicator data operationId: indicatorDsdDataUploadImport parameters: - name: sid in: path required: true schema: type: string requestBody: content: application/json: schema: type: object additionalProperties: true responses: '200': description: Import result '400': description: Bad request # ───────────────────────────────────────────────────────────────────────── # Jobs # ───────────────────────────────────────────────────────────────────────── "/jobs/import_indicator_data": post: tags: - Jobs summary: Import indicator data (full workflow) description: > Submit a single background job that handles the complete indicator data import workflow: copies the uploaded CSV, validates headers against the bound DSD, and publishes rows for the requested `indicator_value` via replace-from-csv. The CSV must be uploaded first via the resumable upload API `POST /upload/{sid}` (initialize session, send chunks, complete) to obtain an `upload_id`. Poll job status via `GET /jobs/{uuid}`. For interactive import in the editor, use `POST /api/indicator_dsd/data_upload_prepare/{sid}` and `POST /api/indicator_dsd/data_upload_import/{sid}` instead. Requires edit access to the target project (same as the indicator DSD import APIs). operationId: importIndicatorDataJob requestBody: required: true content: application/json: schema: type: object required: - project_id - upload_id - indicator_value properties: project_id: oneOf: - type: integer description: Numeric database project id - type: string description: Project idno, or numeric id as a string (same resolution as other editor APIs) description: Indicator/timeseries project — numeric id or idno upload_id: type: string description: Completed upload session ID from `POST /upload/{sid}` indicator_value: type: string description: Value in the DSD indicator_id column; only matching rows are imported delimiter: type: string default: "," description: CSV field delimiter character priority: type: integer default: 0 description: Job queue priority responses: "201": description: Import job created content: application/json: schema: type: object properties: status: type: string example: success uuid: type: string description: Job UUID — use with GET /jobs/{uuid} to poll status job: type: object additionalProperties: true security: - ApiKeyAuth: [] components: requestBodies: timeseries-db-schema.json: content: application/json: schema: $ref: timeseries-db-schema.json required: true survey-schema.json: content: application/json: schema: $ref: survey-schema.json required: true video-schema.json: content: application/json: schema: $ref: video-schema.json required: true table-schema.json: content: application/json: schema: $ref: table-schema.json required: true AddProjectsToCollection: content: application/json: schema: $ref: "#/components/schemas/AddProjectsToCollection" required: true timeseries-schema.json: content: application/json: schema: $ref: timeseries-schema.json required: true geospatial-schema.json: content: application/json: schema: $ref: geospatial-schema.json required: true document-schema.json: content: application/json: schema: $ref: document-schema.json required: true image-schema.json: content: application/json: schema: $ref: image-schema.json required: true script-schema.json: content: application/json: schema: $ref: script-schema.json required: true Collection: content: application/json: schema: $ref: "#/components/schemas/Collection" required: true UserCollectionAccess: content: application/json: schema: $ref: "#/components/schemas/UserCollectionAccess" required: true RemoveUserCollectionAccess: content: application/json: schema: $ref: "#/components/schemas/RemoveUserCollectionAccess" required: true ProjectTemplate: content: application/json: schema: $ref: "#/components/schemas/ProjectTemplate" required: true CatalogConnection: content: application/json: schema: $ref: "#/components/schemas/CatalogConnection" required: true securitySchemes: ApiKeyAuth: type: apiKey in: header name: X-API-Key description: API key for authentication schemas: MetadataChangePatchItem: type: object description: Single metadata change at a JSON Pointer path properties: op: type: string enum: - add - remove - replace path: type: string description: JSON Pointer path (RFC 6901) example: /series_description/ref_country/1 old: description: Value before the change (null for add) nullable: true new: description: Value after the change (null for remove) nullable: true MetadataChangeSummary: type: object properties: added: type: integer removed: type: integer replaced: type: integer MetadataChangeRecordV1: type: object description: > Metadata change payload stored in audit log entries for saves that produced a diff. When diff computation fails, `status` is `diff_failed` and `before`/`after` contain normalized snapshots. properties: version: type: integer example: 1 scope: type: string enum: - study_metadata - admin_metadata - template summary: $ref: "#/components/schemas/MetadataChangeSummary" patch: type: array items: $ref: "#/components/schemas/MetadataChangePatchItem" status: type: string enum: - diff_failed error: type: string before: type: object additionalProperties: true after: type: object additionalProperties: true AuditLogHistoryEntry: type: object properties: id: type: integer obj_type: type: string example: project obj_id: type: integer user_id: type: integer action_type: type: string description: Audit action (e.g. update, patch) example: update created: type: string format: date-time obj_ref_id: type: integer nullable: true metadata: description: Change record or other audit payload oneOf: - $ref: "#/components/schemas/MetadataChangeRecordV1" - type: object additionalProperties: true nullable: true username: type: string nullable: true email: type: string nullable: true PaginatedHistoryMeta: type: object properties: limit: type: integer example: 15 offset: type: integer example: 0 total: type: integer description: Total matching entries found: type: integer description: Number of entries returned in this page ProjectHistoryResponse: allOf: - type: object properties: status: type: string example: success history: type: array items: $ref: "#/components/schemas/AuditLogHistoryEntry" - $ref: "#/components/schemas/PaginatedHistoryMeta" AdminMetadataHistoryResponse: allOf: - type: object properties: status: type: string example: success data: type: array items: $ref: "#/components/schemas/AuditLogHistoryEntry" - $ref: "#/components/schemas/PaginatedHistoryMeta" TemplateRevisionHistoryEntry: type: object properties: id: type: integer obj_type: type: string example: template obj_id: type: integer user_id: type: integer action_type: type: string description: Audit action (e.g. update, patch) created: type: string format: date-time metadata: oneOf: - $ref: "#/components/schemas/MetadataChangeRecordV1" - type: object additionalProperties: true nullable: true username: type: string nullable: true TemplateRevisionHistoryResponse: type: object properties: total: type: integer limit: type: integer example: 15 offset: type: integer example: 0 found: type: integer history: type: array items: $ref: "#/components/schemas/TemplateRevisionHistoryEntry" CreateProjectOverwrite: type: object properties: overwrite: type: boolean default: false description: > If true and a project with the same idno already exists, overwrite its metadata in place instead of returning an error. The existing project must be the same type. Collection memberships and file attachments are preserved. Template: type: object properties: type: type: string template: type: object xml: name: template TemplateForCollection: type: object properties: collection_id: type: integer template_uid: type: string project_type: type: string description: survey, timeseries, table, document, geospatial, ... xml: name: TemplateForCollection Collection: type: object properties: title: type: string description: type: string xml: name: collection CollectionList: type: object properties: id: type: integer title: type: string description: type: string created: type: string format: date-time changed: type: string format: date-time created_by: type: integer format: int64 changed_by: type: integer format: int64 username: type: string xml: name: CollectionList AddProjectsToCollection: type: object properties: collections: type: array items: type: integer id_format: type: string default: id enum: - id - idno projects: type: array items: type: string xml: name: AddProjectsToCollection UserCollectionAccess: type: object properties: collection_id: type: integer user_id: type: integer format: int64 permissions: type: string description: Single collection ACL role per grant (stored as one value in `editor_collection_acl.permissions`). enum: - view - edit - admin example: admin UserCollectionPermissions: type: object properties: status: type: string description: Response status example: success user_id: type: integer format: int64 description: User ID requesting permissions example: 123 is_admin: type: boolean description: Whether user has admin privileges example: false admin_type: type: string description: Type of admin access (global, collection, none) enum: - global - collection - none example: collection collections: type: object description: Collection permissions keyed by collection ID additionalProperties: $ref: "#/components/schemas/CollectionPermission" xml: name: UserCollectionPermissions CollectionPermission: type: object properties: id: type: integer format: int64 description: Collection ID example: 1 title: type: string description: Collection title example: Research Data 2024 description: type: string description: Collection description example: Annual research data collection pid: type: integer format: int64 description: Parent collection ID example: 0 created_by: type: integer format: int64 description: User ID who created the collection example: 123 created: type: string format: date-time description: Collection creation timestamp example: 2024-01-15T10:00:00Z changed: type: string format: date-time description: Collection last modified timestamp example: 2024-03-20T14:30:00Z owner_username: type: string description: Username of collection owner example: john_doe permission_level: type: string description: User's permission level for this collection enum: - view - edit - admin example: edit can_edit: type: boolean description: Whether user can edit this collection example: true can_admin: type: boolean description: Whether user can administer this collection example: false can_delete: type: boolean description: Whether user can delete this collection example: false can_manage_access: type: boolean description: Whether user can manage access to this collection example: false can_add_projects: type: boolean description: Whether user can add projects to this collection example: true can_remove_projects: type: boolean description: Whether user can remove projects from this collection example: true xml: name: CollectionPermission RemoveUserCollectionAccess: type: object properties: collection_id: type: integer user_id: type: integer format: int64 CopyCollection: type: object properties: source_id: type: integer description: Source collection ID target_id: type: integer description: Target collection ID MoveCollection: type: object properties: source_id: type: integer description: Source collection ID target_id: type: integer description: Target collection ID AuthenticationResponse: type: object properties: id: type: integer format: int64 readOnly: true user_id: type: integer username: type: string api-keys: type: object xml: name: AuthenticationResponse Resource: type: object properties: id: type: integer format: int64 readOnly: true pid: type: integer format: int64 description: Project ID resource_type: type: string enum: - microdata - questionnaire - report - table - other title: type: string description: type: string filename: type: string created: type: string format: date-time changed: type: string format: date-time xml: name: Resource CreateAdminMetadataType: type: object required: - name - title - schema_id - schema_urn properties: name: type: string title: Unique name for the metadata type description: Unique name for the metadata type with no spaces or special characters title: type: string title: Title of the metadata type description: type: string title: Description of the metadata type schema_id: type: string title: Schema ID schema_urn: type: string title: Schema URN (only when schema_id is not provided) UpdateAdminMetadataType: type: object required: - name - title - schema_id - schema_urn properties: name: type: string title: Unique name for the metadata type description: Unique name for the metadata type with no spaces or special characters title: type: string title: Title of the metadata type description: type: string title: Description of the metadata type schema_id: type: string title: Schema ID schema_urn: type: string title: Schema URN (only when schema_id is not provided) createAdminMetadataSchema: type: object required: - name - agency - version - title - schema properties: name: type: string title: Unique name for the metadata schema description: Unique name for the metadata schema with no spaces or special characters agency: type: string title: Agency description: Agency/Organization responsible for the schema. Use acronym e.g. IHSN, WBG, etc. version: type: string title: Version description: Version of the schema. Use symantic versioning e.g. 1.0.0 title: type: string title: Title of the metadata schema description: type: string title: Description of the metadata schema schema: type: object title: Schema description: JSON schema for the metadata type CreateAdminMetadataData: type: object required: - project_id - template_uid - metadata properties: project_id: type: string title: Project ID/IDNO description: Project ID or IDNO template_uid: type: string title: Metadata template UID description: Admin metadata template UID metadata: type: object title: Metadata description: Administrative metadata PatchAdminMetadataData: type: object required: - project_id - template_uid - patches properties: project_id: type: string title: Project ID/IDNO description: Project ID or IDNO template_uid: type: string title: Metadata template UID description: Admin metadata template UID patches: type: array title: JSON Patch operations description: Array of JSON patch operations (RFC 6902) items: type: object required: - op - path properties: op: type: string enum: - add - remove - replace - move - copy - test description: Operation type path: type: string description: "JSON Pointer path (RFC 6901) to the element to be patched. Example: /metadata_container/metadata_section/options/0/value" value: description: Value for add or replace operations (can be string, number, boolean, object, or array) from: type: string description: Source path for move or copy operations QueryAdminMetadataData: type: object properties: project_id: type: string title: Project ID/IDNO description: (Optional) Filter by project ID or IDNO template_uid: type: string title: Metadata template UID description: (Optional) Filter by metadata template UID. For multiple templates, use comma separated values offset: type: integer title: Offset description: Offset for pagination limit: type: integer title: Limit description: Limit for pagination RemoveAdminMetadataData: type: object required: - project_id - template_uid properties: project_id: type: string title: Project ID/IDNO description: Project ID or IDNO template_uid: type: string title: Template UID description: Admin metadata template UID ProjectTemplate: type: object properties: template_uid: type: string description: Template UID xml: name: ProjectTemplate ProjectOptionsIDNO: type: object properties: idno: type: string description: New IDNO for the project xml: name: ProjectOptionsIDNO CatalogConnection: type: object properties: title: type: string description: Catalog connection title url: type: string description: URL of the catalog e.g. https://your-nada-catalog.org api_key: type: string description: API key for your NADA catalog xml: name: CatalogConnection CatalogConnectionDelete: type: object properties: catalog_id: type: integer description: Catalog connection ID xml: name: CatalogConnectionDelete CreateProjectVersion: type: object required: - id - version_type - version_notes properties: id: type: string description: Project ID or IDNO version_type: type: string description: Type of version to create enum: - major - minor - patch version_notes: type: string description: Notes describing the version xml: name: CreateProjectVersion DuplicateProjectResponse: type: object properties: status: type: string example: success result: $ref: "#/components/schemas/DuplicateProjectResult" DuplicateProjectResult: type: object properties: source_id: type: integer description: ID of the source project id: type: integer description: ID of the new duplicated project idno: type: string description: Generated UUID idno for the new project title: type: string description: Title of the new project (source title with " (copy)" suffix) type: type: string description: Project type (same as source) template_uid: type: string description: Template UID (same as source) project_folder: type: string description: Relative storage path for the new project folder project_dsd: type: object nullable: true description: Indicator DSD binding copy result, or null if not applicable properties: data_structure_id: type: integer has_published_data: type: integer description: Always 0 for duplicates (DuckDB not copied) xml: name: DuplicateProjectResult DeleteProjectVersion: type: object required: - id - version properties: id: type: string description: Project ID or IDNO for the main project version: type: string description: Version number to delete (e.g. 1.0.0) xml: name: DeleteProjectVersion DeleteProjectVersionById: type: object required: - id - version properties: id: type: string description: Project ID or IDNO for the version to delete xml: name: DeleteProjectVersionById PublishOptions: type: object description: > Fields merged into the exported project JSON before POST to NADA. Names and values follow the Metadata Editor publish UI and NADA dataset-create expectations. Any additional JSON properties are also merged if supplied. properties: overwrite: type: string enum: - "yes" - "no" default: "no" description: > If `yes`, allows replacing an existing study in the catalog with the same IDNO. Merged as top-level `overwrite` on the dataset JSON sent to NADA. published: type: integer format: int32 enum: - 0 - 1 description: Catalog visibility — `0` draft, `1` published (merged as `published`). access_policy: type: string description: > Data access / access policy code merged as `access_policy` on the payload. Allowed values match the Metadata Editor publish form; NADA may validate against codes returned by `GET .../index.php/api/catalog/data_access_codes` on the catalog. enum: - data_na - direct - public - licensed - remote - enclave - open - "" default: data_na data_remote_url: type: string description: > URL for remote / external data access; merged as `data_remote_url`. Used when `access_policy` is `remote` or `enclave` (per catalog configuration). repositoryid: type: string description: > Target collection (repository) code in NADA; merged as `repositoryid`. Options are typically populated from `GET .../index.php/api/collections` on the catalog (see `/publish/catalog_info/...`). additionalProperties: true example: overwrite: "yes" published: 1 access_policy: licensed data_remote_url: "" repositoryid: MY_COLLECTION xml: name: PublishOptions NadaCatalogInfoResponse: type: object description: Response from prefetching NADA data for the publish form properties: study_info: type: object description: > Outcome of `GET {catalog}/index.php/api/datasets/{study_idno}`. On success, normalized fields from `dataset` (without embedded `metadata`) plus `status: success`. On failure, includes `status` (`error` or `failed`), `error` message, optional `response`, and `api_url`. collections_codes: type: array description: Entries from NADA `GET .../index.php/api/collections` (`collections` array) items: type: object additionalProperties: true data_access_codes: type: array description: > Codes from NADA `GET .../index.php/api/catalog/data_access_codes` (`codes` array); used to populate the data access / access_policy control. items: type: object additionalProperties: true collections_linked: type: array description: > Collections already associated with the study from NADA `GET .../index.php/api/datasets/collections/{study_idno}` (normalized list). items: type: object additionalProperties: true indicator_publish: $ref: "#/components/schemas/IndicatorPublishPrefetch" IndicatorPublishPrefetch: type: object description: > Prefetched indicator DSD/data status for the publish UI (indicator/timeseries projects only). properties: local: type: object additionalProperties: true nada_dsd: type: object nullable: true additionalProperties: true nada_data: type: object nullable: true additionalProperties: true prefetch_error: type: string nullable: true IndicatorPublishOptions: type: object properties: publish_dsd: type: boolean description: Publish bound DSD to NADA default: false dsd_overwrite: type: boolean description: Replace DSD on NADA when it already exists default: false publish_indicator_data: type: boolean description: Export DuckDB timeseries CSV and import observations to NADA default: false nada_upload_id: type: string description: > Completed NADA resumable upload_id from step-by-step publish (skips export and upload; import-only). Requires publish_indicator_data true. IndicatorPublishResponse: type: object properties: dsd: type: object nullable: true additionalProperties: true data: type: object nullable: true additionalProperties: true DataStructureStatusCode: type: string description: >- Catalogue DSD lifecycle slug (persisted as an integer in `data_structures.status`): `draft`, `review`, `published` (locked from destructive edits), `deprecated`, `archived` (locked). Request bodies and import JSON must use these strings. enum: [draft, review, published, deprecated, archived] DataStructureReference: type: object description: >- Canonical link to a global catalogue DSD stored on project/study metadata. Matches `data_structure_reference` in `timeseries-schema.json`. required: [idno, agency, name, version] properties: idno: type: string description: Stable catalogue DSD idno agency: type: string name: type: string description: SDMX maintainable id version: type: string uri: type: string format: uri description: Optional URL for documentation or discovery; not used for import notes: type: string description: Optional free-text notes about this DSD link additionalProperties: false IndicatorDsdBindRequest: type: object description: Bind a global registry DSD to a project properties: data_structure_id: type: integer description: Numeric catalogue data structure id data_structure_reference: $ref: '#/components/schemas/DataStructureReference' indicator_id_value: type: string description: Value for the DSD indicator_id column used during data import ApiStatusFailed: type: object required: [status, message] properties: status: type: string enum: [failed] message: type: string error: type: string description: Present on some ACL denials (`Access denied`) CodelistStatusCode: type: string description: Catalogue codelist lifecycle status enum: [draft, active, locked, archived] CodelistCatalogRow: type: object description: Global codelist header row (list/detail shapes vary slightly by endpoint) properties: id: type: integer idno: type: string agency: type: string name: type: string description: SDMX maintainable id version: type: string title: type: string description: type: string status: $ref: '#/components/schemas/CodelistStatusCode' item_count: type: integer description: Present when with_counts is enabled dsd_component_count: type: integer description: Present when with_counts is enabled versions_count: type: integer description: Present on collapsed family rows additionalProperties: true CodelistListResponse: type: object required: [status, codelists, total] properties: status: type: string enum: [success] codelists: type: array items: $ref: '#/components/schemas/CodelistCatalogRow' total: type: integer page: type: integer per_page: type: integer collapsed: type: boolean offset: type: integer limit: type: integer CodelistVersionsResponse: type: object required: [status, codelists] properties: status: type: string enum: [success] codelists: type: array items: $ref: '#/components/schemas/CodelistCatalogRow' CodelistSingleResponse: type: object required: [status, codelist] properties: status: type: string enum: [success] codelist: $ref: '#/components/schemas/CodelistCatalogRow' CodelistCreateRequest: type: object required: [agency, name, version, title] properties: agency: type: string name: type: string version: type: string title: type: string description: type: string status: $ref: '#/components/schemas/CodelistStatusCode' additionalProperties: true CodelistCreateResponse: type: object required: [status, id] properties: status: type: string enum: [success] id: type: integer message: type: string CodelistMutationResponse: type: object required: [status] properties: status: type: string enum: [success] id: type: integer message: type: string CodelistCodesResponse: type: object required: [status, codes, total] properties: status: type: string enum: [success] total: type: integer offset: type: integer limit: type: integer nullable: true codes: type: array items: type: object additionalProperties: true CodelistImportResponse: type: object properties: status: type: string dry_run: type: boolean imported: type: array items: type: object additionalProperties: true warnings: type: array items: type: string additionalProperties: true IndicatorDsdStructureValidationBlock: type: object properties: valid: type: boolean errors: type: array items: type: string warnings: type: array items: type: string summary: type: object additionalProperties: true roles: type: object additionalProperties: true description: Role checklist (required/recommended column counts by column_type) IndicatorDsdDataValidationBlock: type: object properties: skipped: type: boolean description: When true, data checks were not run (see reason) has_data: type: boolean source: type: string nullable: true description: e.g. published timeseries when data was checked valid: type: boolean nullable: true description: Null when data validation was skipped errors: type: array items: type: string warnings: type: array items: type: string reason: type: string nullable: true row_count: type: integer nullable: true observation_key: type: object nullable: true additionalProperties: true description: Observation-key column list and uniqueness stats when applicable IndicatorDsdValidateResponse: type: object required: [status, valid] properties: status: type: string enum: [success, failed] description: Mirrors overall validation outcome valid: type: boolean description: False when structure or data validation has errors errors: type: array items: type: string warnings: type: array items: type: string summary: type: object additionalProperties: true structure: $ref: '#/components/schemas/IndicatorDsdStructureValidationBlock' data_validation: $ref: '#/components/schemas/IndicatorDsdDataValidationBlock' IndicatorDsdBindingResponse: type: object required: [status, bound, import_ready] properties: status: type: string enum: [success] bound: type: boolean read_only: type: boolean description: True when a global DSD is bound (structure is registry-managed) binding: type: object nullable: true additionalProperties: true description: Project DSD binding row from editor_project_dsd data_structure_reference: $ref: '#/components/schemas/DataStructureReference' global_structure: type: object nullable: true additionalProperties: true description: Global data structure header when bound column_count: type: integer indicator_id_value: type: string nullable: true series_idno: type: string nullable: true default_indicator_id_value: type: string nullable: true indicator_id_column: type: string nullable: true description: DSD column name with column_type indicator_id has_periodicity_column: type: boolean needs_implied_freq_code: type: boolean implied_freq_code: type: string nullable: true has_published_data: type: boolean published_row_count: type: integer nullable: true data_imported_at: type: integer nullable: true description: Unix timestamp when data was last imported import_ready: type: boolean import_blocked_reasons: type: array items: type: string structure_validation: $ref: '#/components/schemas/IndicatorDsdStructureValidationBlock' freq_codes: type: array items: type: object properties: code: type: string label: type: string additionalProperties: true IndicatorDsdCsvIndicatorValue: type: object properties: value: type: string count: type: integer nullable: true IndicatorDsdDataUploadPrepareResponse: type: object required: [status, headers_valid] properties: status: type: string enum: [success] headers_valid: type: boolean enum: [true] expected_columns: type: array items: type: string description: DSD column names required in the CSV import_columns: type: array items: type: string description: Column names passed to the DuckDB import keep_extra_csv_columns: type: boolean indicator_column: type: string description: DSD column name for indicator_id indicator_id_value: type: string nullable: true description: Bound value on the project (may be empty at prepare time) indicator_values: type: array items: $ref: '#/components/schemas/IndicatorDsdCsvIndicatorValue' description: Distinct indicator_id values found in the CSV indicator_values_truncated: type: boolean indicator_values_limit: type: integer series_idno: type: string nullable: true series_idno_in_csv: type: boolean ignored_columns: type: array items: type: string description: Extra CSV columns not in the DSD extra_in_csv: type: array items: type: string csv_row_count: type: integer nullable: true IndicatorDsdDataUploadPrepareHeaderError: type: object required: [status, headers_valid] properties: status: type: string enum: [failed] headers_valid: type: boolean enum: [false] message: type: string missing_in_csv: type: array items: type: string ignored_columns: type: array items: type: string extra_in_csv: type: array items: type: string expected_columns: type: array items: type: string ApiResponse: type: object properties: code: type: integer format: int32 type: type: string message: type: string