Files
Steve Munene 7f03134d8e
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
NOISSUE - Update bootstrap and provision service (#3476)
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
Signed-off-by: JeffMboya <jangina.mboya@gmail.com>
Co-authored-by: JeffMboya <jangina.mboya@gmail.com>
2026-05-08 10:35:00 +02:00

1152 lines
34 KiB
YAML

# Copyright (c) Abstract Machines
# SPDX-License-Identifier: Apache-2.0
openapi: 3.0.1
info:
title: Magistrala Bootstrap service
description: |
HTTP API for managing platform clients configuration, device profiles,
and enrollment bindings.
Some useful links:
- [The Magistrala repository](https://github.com/absmach/magistrala)
contact:
email: info@absmach.eu
license:
name: Apache 2.0
url: https://github.com/absmach/magistrala/blob/main/LICENSE
version: 0.19.0
servers:
- url: http://localhost:9013
- url: https://localhost:9013
tags:
- name: configs
description: Bootstrap enrollment configurations
externalDocs:
description: Find out more about Configs
url: https://magistrala.absmach.eu/docs/
- name: profiles
description: Device configuration profiles and templates
- name: enrollments
description: Enrollment profile assignment and resource bindings
paths:
# ── Enrollment configs ────────────────────────────────────────────────────
/{domainID}/clients/configs:
post:
operationId: createConfig
summary: Adds a new enrollment config
description: |
Adds a new bootstrap enrollment config owned by the user identified by
the provided access token.
tags:
- configs
parameters:
- $ref: "#/components/parameters/DomainID"
requestBody:
$ref: "#/components/requestBodies/ConfigCreateReq"
responses:
"201":
$ref: "#/components/responses/ConfigCreateRes"
"400":
description: Failed due to malformed JSON.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"409":
description: Failed due to using an existing external ID.
"415":
description: Missing or invalid content type.
"500":
$ref: "#/components/responses/ServiceError"
get:
operationId: getConfigs
summary: Retrieves managed configs
description: |
Retrieves a paginated list of managed enrollment configs.
tags:
- configs
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/Offset"
- $ref: "#/components/parameters/Status"
- $ref: "#/components/parameters/Name"
responses:
"200":
$ref: "#/components/responses/ConfigListRes"
"400":
description: Failed due to malformed query parameters.
"401":
description: Missing or invalid access token provided.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/clients/configs/{configID}:
get:
operationId: getConfig
summary: Retrieves a config
tags:
- configs
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ConfigID"
responses:
"200":
$ref: "#/components/responses/ConfigRes"
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"404":
description: Config does not exist.
"500":
$ref: "#/components/responses/ServiceError"
patch:
operationId: updateConfig
summary: Updates config info
description: |
Updates name and content of an existing enrollment config.
tags:
- configs
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ConfigID"
requestBody:
$ref: "#/components/requestBodies/ConfigUpdateReq"
responses:
"200":
description: Config updated.
"400":
description: Failed due to malformed JSON.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"404":
description: Config does not exist.
"415":
description: Missing or invalid content type.
"500":
$ref: "#/components/responses/ServiceError"
delete:
operationId: removeConfig
summary: Removes a config
tags:
- configs
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ConfigID"
responses:
"204":
description: Config removed.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/clients/configs/certs/{configID}:
patch:
operationId: updateConfigCerts
summary: Updates client certificates
description: |
Replaces the certificate fields (client_cert, client_key, ca_cert) of an
existing enrollment config.
tags:
- configs
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ConfigID"
requestBody:
$ref: "#/components/requestBodies/ConfigCertUpdateReq"
responses:
"200":
$ref: "#/components/responses/ConfigUpdateCertsRes"
"400":
description: Failed due to malformed JSON.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"404":
description: Config does not exist.
"415":
description: Missing or invalid content type.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/clients/configs/{configID}/enable:
post:
operationId: enableConfig
summary: Enables a config
description: |
Enables the enrollment config, allowing its device to bootstrap.
Idempotent — returns the current config without error if already enabled.
tags:
- configs
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ConfigID"
responses:
"200":
$ref: "#/components/responses/ConfigRes"
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"404":
description: Config does not exist.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/clients/configs/{configID}/disable:
post:
operationId: disableConfig
summary: Disables a config
description: |
Disables the enrollment config, preventing its device from bootstrapping.
Idempotent — returns the current config without error if already disabled.
tags:
- configs
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ConfigID"
responses:
"200":
$ref: "#/components/responses/ConfigRes"
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"404":
description: Config does not exist.
"500":
$ref: "#/components/responses/ServiceError"
# ── Device bootstrap ──────────────────────────────────────────────────────
/clients/bootstrap/{externalID}:
get:
operationId: getBootstrapConfig
summary: Retrieves a bootstrap configuration
description: |
Returns the rendered bootstrap configuration for a device identified by
its external ID and external key.
tags:
- configs
security:
- bootstrapAuth: []
parameters:
- $ref: "#/components/parameters/ExternalID"
responses:
"200":
$ref: "#/components/responses/BootstrapConfigRes"
"400":
description: Missing or invalid external ID.
"401":
description: Missing or invalid external key.
"403":
description: Config is disabled.
"404":
description: No config found for the given external ID.
"500":
$ref: "#/components/responses/ServiceError"
/clients/bootstrap/secure/{externalID}:
get:
operationId: getSecureBootstrapConfig
summary: Retrieves an encrypted bootstrap configuration
description: |
Returns the rendered bootstrap configuration encrypted with the device's
AES key. The external key must be hex-encoded and AES-encrypted.
tags:
- configs
security:
- bootstrapEncAuth: []
parameters:
- $ref: "#/components/parameters/ExternalID"
responses:
"200":
description: Encrypted bootstrap payload (binary).
content:
application/octet-stream:
schema:
type: string
format: binary
"400":
description: Missing or invalid external ID.
"401":
description: Missing or invalid encrypted external key.
"403":
description: Config is disabled.
"404":
description: No config found for the given external ID.
"500":
$ref: "#/components/responses/ServiceError"
# ── Device profiles ───────────────────────────────────────────────────────
/{domainID}/clients/bootstrap/profiles:
post:
operationId: createProfile
summary: Creates a device profile
tags:
- profiles
parameters:
- $ref: "#/components/parameters/DomainID"
requestBody:
$ref: "#/components/requestBodies/ProfileCreateReq"
responses:
"201":
$ref: "#/components/responses/ProfileRes"
"400":
description: Failed due to malformed JSON.
"401":
description: Missing or invalid access token provided.
"403":
description: Failed to perform authorization over the entity.
"409":
description: A profile with the same name already exists in this domain.
"415":
description: Missing or invalid content type.
"500":
$ref: "#/components/responses/ServiceError"
get:
operationId: listProfiles
summary: Lists device profiles
tags:
- profiles
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/Limit"
- $ref: "#/components/parameters/Offset"
responses:
"200":
$ref: "#/components/responses/ProfileListRes"
"400":
description: Failed due to malformed query parameters.
"401":
description: Missing or invalid access token provided.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/clients/bootstrap/profiles/upload:
post:
operationId: uploadProfile
summary: Uploads a device profile
description: |
Uploads a profile definition. Accepts JSON, YAML, or TOML payloads
depending on the Content-Type header.
tags:
- profiles
parameters:
- $ref: "#/components/parameters/DomainID"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Profile"
application/yaml:
schema:
$ref: "#/components/schemas/Profile"
application/toml:
schema:
$ref: "#/components/schemas/Profile"
responses:
"201":
$ref: "#/components/responses/ProfileRes"
"400":
description: Failed due to malformed body.
"401":
description: Missing or invalid access token provided.
"415":
description: Unsupported content type.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/clients/bootstrap/profiles/{profileID}:
get:
operationId: getProfile
summary: Retrieves a device profile
tags:
- profiles
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ProfileID"
responses:
"200":
$ref: "#/components/responses/ProfileRes"
"401":
description: Missing or invalid access token provided.
"404":
description: Profile does not exist.
"500":
$ref: "#/components/responses/ServiceError"
patch:
operationId: updateProfile
summary: Updates a device profile
tags:
- profiles
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ProfileID"
requestBody:
$ref: "#/components/requestBodies/ProfileUpdateReq"
responses:
"200":
$ref: "#/components/responses/ProfileRes"
"400":
description: Failed due to malformed JSON.
"401":
description: Missing or invalid access token provided.
"404":
description: Profile does not exist.
"415":
description: Missing or invalid content type.
"500":
$ref: "#/components/responses/ServiceError"
delete:
operationId: deleteProfile
summary: Deletes a device profile
tags:
- profiles
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ProfileID"
responses:
"204":
description: Profile deleted.
"401":
description: Missing or invalid access token provided.
"404":
description: Profile does not exist.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/clients/bootstrap/profiles/{profileID}/slots:
get:
operationId: getProfileSlots
summary: Retrieves the binding slots declared by a profile
tags:
- profiles
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ProfileID"
responses:
"200":
description: Binding slots retrieved.
content:
application/json:
schema:
type: object
properties:
slots:
type: array
items:
$ref: "#/components/schemas/BindingSlot"
"401":
description: Missing or invalid access token provided.
"404":
description: Profile does not exist.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/clients/bootstrap/profiles/{profileID}/render-preview:
post:
operationId: renderPreview
summary: Renders a profile template preview
description: |
Renders the profile's content template with the supplied device context
and binding snapshots. No external service calls are made — all data
must be supplied in the request body.
tags:
- profiles
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ProfileID"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
config:
$ref: "#/components/schemas/Config"
render_context:
type: object
additionalProperties: true
description: Per-device variable overrides.
bindings:
type: array
items:
$ref: "#/components/schemas/BindingSnapshot"
responses:
"200":
description: Rendered template output.
content:
application/json:
schema:
type: object
properties:
rendered:
type: string
"400":
description: Template rendering failed.
"401":
description: Missing or invalid access token provided.
"404":
description: Profile does not exist.
"500":
$ref: "#/components/responses/ServiceError"
# ── Enrollment bindings ───────────────────────────────────────────────────
/{domainID}/clients/bootstrap/enrollments/{configID}/profile:
patch:
operationId: assignProfile
summary: Assigns a profile to an enrollment
tags:
- enrollments
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ConfigID"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
profile_id:
type: string
format: uuid
required:
- profile_id
responses:
"200":
description: Profile assigned.
"400":
description: Failed due to malformed JSON.
"401":
description: Missing or invalid access token provided.
"404":
description: Config or profile does not exist.
"415":
description: Missing or invalid content type.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/clients/bootstrap/enrollments/{configID}/bindings:
put:
operationId: bindResources
summary: Binds resources to profile slots
description: |
Resolves the requested resource bindings via their owning services,
stores snapshots, and marks the enrollment renderable when all required
slots are satisfied.
tags:
- enrollments
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ConfigID"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
bindings:
type: array
minItems: 1
items:
$ref: "#/components/schemas/BindingRequest"
required:
- bindings
responses:
"200":
description: Bindings stored.
"400":
description: Failed due to malformed JSON or invalid binding request.
"401":
description: Missing or invalid access token provided.
"404":
description: Config or resource not found.
"415":
description: Missing or invalid content type.
"500":
$ref: "#/components/responses/ServiceError"
get:
operationId: listBindings
summary: Lists binding snapshots for an enrollment
tags:
- enrollments
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ConfigID"
responses:
"200":
$ref: "#/components/responses/BindingsRes"
"401":
description: Missing or invalid access token provided.
"404":
description: Config does not exist.
"500":
$ref: "#/components/responses/ServiceError"
/{domainID}/clients/bootstrap/enrollments/{configID}/bindings/refresh:
post:
operationId: refreshBindings
summary: Refreshes all binding snapshots
description: |
Re-resolves every existing binding for the enrollment and updates the
stored snapshots with current resource data.
tags:
- enrollments
parameters:
- $ref: "#/components/parameters/DomainID"
- $ref: "#/components/parameters/ConfigID"
responses:
"200":
description: Bindings refreshed.
"401":
description: Missing or invalid access token provided.
"404":
description: Config does not exist.
"500":
$ref: "#/components/responses/ServiceError"
# ── Health ────────────────────────────────────────────────────────────────
/health:
get:
summary: Retrieves service health check info.
tags:
- health
security: []
responses:
"200":
$ref: "#/components/responses/HealthRes"
"500":
$ref: "#/components/responses/ServiceError"
components:
schemas:
Status:
type: string
enum: [enabled, disabled]
description: Enrollment status.
Config:
type: object
properties:
id:
type: string
format: uuid
description: Enrollment ID.
domain_id:
type: string
format: uuid
description: Domain the enrollment belongs to.
external_id:
type: string
description: External device identifier (e.g. MAC address).
external_key:
type: string
description: External authentication key (write-only; not returned after creation).
name:
type: string
description: Human-readable name.
content:
type: string
description: Legacy free-form configuration payload.
status:
$ref: "#/components/schemas/Status"
profile_id:
type: string
format: uuid
description: ID of the device profile used for template rendering.
render_context:
type: object
additionalProperties: true
description: Per-device variable values injected into the profile template.
client_cert:
type: string
description: Client TLS certificate (PEM).
client_key:
type: string
description: Client TLS private key (PEM).
ca_cert:
type: string
description: CA certificate (PEM).
required:
- external_id
- external_key
ConfigList:
type: object
properties:
total:
type: integer
minimum: 0
offset:
type: integer
minimum: 0
default: 0
limit:
type: integer
maximum: 100
default: 10
configs:
type: array
items:
$ref: "#/components/schemas/Config"
required:
- configs
BootstrapConfig:
type: object
description: Rendered configuration returned to a bootstrapping device.
properties:
id:
type: string
format: uuid
description: Enrollment ID.
content:
type: string
description: Rendered configuration payload.
client_cert:
type: string
description: Client TLS certificate (PEM).
client_key:
type: string
description: Client TLS private key (PEM).
ca_cert:
type: string
description: CA certificate (PEM).
ConfigUpdateCerts:
type: object
properties:
id:
type: string
format: uuid
client_cert:
type: string
client_key:
type: string
ca_cert:
type: string
domain_id:
type: string
format: uuid
Profile:
type: object
properties:
id:
type: string
format: uuid
readOnly: true
domain_id:
type: string
format: uuid
readOnly: true
name:
type: string
description:
type: string
template_format:
type: string
enum: [go-template, raw]
default: go-template
content_template:
type: string
description: Template text rendered at bootstrap time.
defaults:
type: object
additionalProperties: true
description: Default variable values merged with per-device render_context.
binding_slots:
type: array
items:
$ref: "#/components/schemas/BindingSlot"
description: Named resource slots declared by this profile.
version:
type: integer
readOnly: true
created_at:
type: string
format: date-time
readOnly: true
updated_at:
type: string
format: date-time
readOnly: true
required:
- name
- template_format
ProfileList:
type: object
properties:
total:
type: integer
minimum: 0
offset:
type: integer
minimum: 0
limit:
type: integer
maximum: 100
profiles:
type: array
items:
$ref: "#/components/schemas/Profile"
BindingSlot:
type: object
description: A named resource placeholder declared by a profile.
properties:
name:
type: string
description: Slot name referenced in the template (e.g. "mqtt_client").
type:
type: string
enum: [client, channel, cert]
description: Expected resource type.
required:
type: boolean
default: true
description: Whether the slot must be bound before the device can bootstrap.
fields:
type: array
items:
type: string
description: Resource fields snapshotted at binding time.
required:
- name
- type
BindingRequest:
type: object
description: A request to bind a profile slot to a concrete resource.
properties:
slot:
type: string
description: Profile slot name to fill.
type:
type: string
enum: [client, channel, cert]
resource_id:
type: string
format: uuid
description: ID of the resource in its owning service.
required:
- slot
- type
- resource_id
BindingSnapshot:
type: object
description: Bootstrap-owned snapshot of a bound resource.
properties:
config_id:
type: string
format: uuid
slot:
type: string
type:
type: string
resource_id:
type: string
format: uuid
snapshot:
type: object
additionalProperties: true
description: Non-secret resource fields captured at binding time.
updated_at:
type: string
format: date-time
parameters:
ConfigID:
name: configID
description: Unique enrollment config identifier.
in: path
schema:
type: string
format: uuid
required: true
ProfileID:
name: profileID
description: Unique profile identifier.
in: path
schema:
type: string
format: uuid
required: true
ExternalID:
name: externalID
description: External device identifier provided at registration.
in: path
schema:
type: string
required: true
DomainID:
name: domainID
description: Unique domain identifier.
in: path
schema:
type: string
format: uuid
required: true
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
Limit:
name: limit
description: Maximum number of items to return.
in: query
schema:
type: integer
default: 10
maximum: 100
minimum: 1
required: false
Offset:
name: offset
description: Number of items to skip.
in: query
schema:
type: integer
default: 0
minimum: 0
required: false
Status:
name: status
description: Filter by enrollment status.
in: query
schema:
$ref: "#/components/schemas/Status"
required: false
Name:
name: name
description: Filter by name (partial, case-insensitive match).
in: query
schema:
type: string
required: false
requestBodies:
ConfigCreateReq:
description: New enrollment config.
required: true
content:
application/json:
schema:
type: object
properties:
external_id:
type: string
external_key:
type: string
name:
type: string
content:
type: string
profile_id:
type: string
format: uuid
render_context:
type: object
additionalProperties: true
client_cert:
type: string
client_key:
type: string
ca_cert:
type: string
required:
- external_id
- external_key
ConfigUpdateReq:
description: Fields to update on an enrollment config.
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
content:
type: string
ConfigCertUpdateReq:
description: Replacement certificate fields.
required: true
content:
application/json:
schema:
type: object
properties:
client_cert:
type: string
client_key:
type: string
ca_cert:
type: string
ProfileCreateReq:
description: New device profile.
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Profile"
ProfileUpdateReq:
description: Updated device profile fields. All fields are optional.
required: true
content:
application/json:
schema:
type: object
properties:
name:
type: string
description:
type: string
template_format:
type: string
enum: [go-template, raw]
content_template:
type: string
defaults:
type: object
additionalProperties: true
binding_slots:
type: array
items:
$ref: "#/components/schemas/BindingSlot"
responses:
ConfigCreateRes:
description: Config registered.
headers:
Location:
schema:
type: string
description: Relative URL of the created config (e.g. /clients/configs/{configID}).
content:
application/json:
schema:
$ref: "#/components/schemas/Config"
ConfigListRes:
description: Configs retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/ConfigList"
ConfigRes:
description: Config retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/Config"
ConfigUpdateCertsRes:
description: Config certificates updated.
content:
application/json:
schema:
$ref: "#/components/schemas/ConfigUpdateCerts"
BootstrapConfigRes:
description: |
Rendered bootstrap configuration. For the secure endpoint the response
body is AES-encrypted binary rather than JSON.
content:
application/json:
schema:
$ref: "#/components/schemas/BootstrapConfig"
ProfileRes:
description: Profile retrieved or created.
content:
application/json:
schema:
$ref: "#/components/schemas/Profile"
ProfileListRes:
description: Profiles retrieved.
content:
application/json:
schema:
$ref: "#/components/schemas/ProfileList"
BindingsRes:
description: Binding snapshots retrieved.
content:
application/json:
schema:
type: object
properties:
bindings:
type: array
items:
$ref: "#/components/schemas/BindingSnapshot"
ServiceError:
description: Unexpected server-side error occurred.
HealthRes:
description: Service health check.
content:
application/health+json:
schema:
$ref: "./schemas/health_info.yaml"
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
User access token: "Authorization: Bearer <user_token>"
bootstrapAuth:
type: http
scheme: bearer
bearerFormat: string
description: |
Device access: "Authorization: Client <external_key>"
bootstrapEncAuth:
type: http
scheme: bearer
bearerFormat: aes-uuid
description: |
Device access with AES-encrypted key: "Authorization: Client <external_enc_key>"
The external key must be hex-encoded and encrypted with AES using the
SHA256 of the external key itself as the encryption key.
security:
- bearerAuth: []