Import Resources
ThunderID provides the POST /import API to import declarative YAML content into runtime stores.
Declarative resource attributes use camelCase (for example ouId, authFlowId, clientId), matching the REST API.
An application resource requires a type attribute (browser, fullstack, mobile, m2m, or custom). The type is set on creation and does not change on a later import. See Application Types.
Use this API when you want to:
- Bootstrap resources from a YAML bundle.
- Apply declarative updates in CI/CD.
- Test resource definitions before applying them.
Authentication and authorization
Use an access token with the system scope.
Send the token in the Authorization header:
Authorization: Bearer <access_token>
Endpoint Summary
POST /import: Imports one or more YAML documents into runtime stores.POST /import/delete: Deletes a file-backed declarative resource file by type and key.
Request Model
POST /import accepts the following payload:
{
"content": "# YAML content with one or more documents",
"variables": {
"CLIENT_ID": "my-client-id"
},
"dryRun": false,
"deletions": [
{
"resourceType": "application",
"id": "550e8400-e29b-41d4-a716-446655440000"
}
],
"options": {
"upsert": true,
"continueOnError": true,
"target": "runtime"
}
}
A request has to carry work to do: content to upsert, deletions to remove, or both. A request
carrying neither is rejected.
Options Behavior
options.upsert:- Omitted: defaults to
true. true: updates existing resources when supported.false: skips update behavior and attempts create semantics.
- Omitted: defaults to
options.continueOnError:- Omitted: defaults to
true. true: continues processing remaining documents after an item failure.false: stops at the first failed item.
- Omitted: defaults to
options.target:- Omitted: defaults to
runtime. runtimeis currently supported.
- Omitted: defaults to
Removing Resources
content can create and update but never remove, so a resource dropped from a configuration would
otherwise linger on every deployment that configuration was applied to. deletions names the
resources to remove, so one request can reconcile a deployment with the configuration as it now
stands.
Each entry names a resourceType and an id. User types and agent types are separate resource
types, user_type and agent_type, as they are in content.
{
"deletions": [
{ "resourceType": "application", "id": "550e8400-e29b-41d4-a716-446655440000" },
{ "resourceType": "agent_type", "id": "660e8400-e29b-41d4-a716-446655440001" }
]
}
Deletion Behavior
- Removals run after the upserts. A resource this same request moved or replaced is in place before its predecessor is pruned.
- Removals are ordered as the reverse of the import dependency order, so a dependent goes before what it depends on rather than failing on a reference that is still live.
- Removing something already absent is a success. Re-applying the same configuration has to be a
no-op, and a request that failed because the removal already happened would make retrying
impossible. Where the service reports not found, the outcome carries the message
resource already absentand does not add tosummary.deleted. - A type with no runtime delete is reported, not skipped.
translationandserver_configare reported as an unsupported outcome, because a configuration that dropped one would otherwise look reconciled when it is not. - A removal the owning service refuses is reported with its reason. An
agent_typedeletion fails withUSRS-1015, because agent creation depends on the default agent type. - A dry run reports what it would remove and removes nothing.
deletionsalone is a valid request. Removing what a configuration dropped does not require also restating what it kept.
Deletions follow options.continueOnError as documents do: by default one refused removal does not
hold back the rest.
Response Model
A successful import returns summary metrics and per-document outcomes.
{
"summary": {
"totalDocuments": 2,
"imported": 2,
"deleted": 1,
"failed": 0,
"importedAt": "2026-04-23T12:10:52Z"
},
"results": [
{
"resourceType": "connection",
"resourceId": "550e8400-e29b-41d4-a716-446655440000",
"resourceName": "Google",
"operation": "create",
"status": "success"
},
{
"resourceType": "flow",
"resourceId": "660e8400-e29b-41d4-a716-446655440001",
"resourceName": "Default Login Flow",
"operation": "update",
"status": "success"
},
{
"resourceType": "application",
"resourceId": "550e8400-e29b-41d4-a716-446655440000",
"operation": "delete",
"status": "success"
}
]
}
summary.deleted counts the deletions this request completed, separately from imported. A dry
run completes none, and a resource a service reports as not found is not counted, though both are
still reported as a success in results. Not every service distinguishes an absent id from a
removed one, so treat this as the number of deletions that completed rather than a guarantee that
each one had something to remove. Every deletion appears in results with operation set to
delete, and that list is where the per-resource outcome is.
Example: Import with Variables
curl -X POST "https://localhost:8090/import" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"content": "resource_type: application\nname: Console\ntype: browser\nauthFlowId: {{.AUTH_FLOW_ID}}\n",
"variables": {
"AUTH_FLOW_ID": "edc013d0-e893-4dc0-990c-3e1d203e005b"
},
"dryRun": false,
"options": {
"upsert": true,
"continueOnError": true,
"target": "runtime"
}
}'
Cross-Resource References by Handle
Instead of embedding environment-specific resource identifiers in YAML files, you can reference organization units and flows by their human-readable handles. The importer resolves each handle to its resource identifier at import time, making the same YAML portable across environments.
The following handle fields are supported:
| Resource type | Handle field | Resolves to |
|---|---|---|
| Application | ouHandle | ouId |
| Application | authFlowHandle | authFlowId |
| Application | registrationFlowHandle | registrationFlowId |
| Application | recoveryFlowHandle | recoveryFlowId |
| Agent | authFlowHandle | authFlowId |
| Agent | registrationFlowHandle | registrationFlowId |
| User type | ouHandle | ouId |
If you provide both a handle field and the corresponding ID field, the ID takes precedence and the handle is ignored.
Updating an existing application or agent with a document that sets only a handle field re-resolves it and keeps the resolved ID.
If a handle cannot be resolved (because the target resource does not exist or the required adapter is not configured), the import item fails with a descriptive error message. When continueOnError is true, the importer continues processing the remaining documents.
Example: Application with Handle References
resource_type: application
name: My App
type: fullstack
ouHandle: default
authFlowHandle: default-basic-flow
registrationFlowHandle: default-registration-flow
isRegistrationFlowEnabled: true
Dry-Run Behavior
When dryRun is true, the importer validates documents and reports what would be created or updated, but does not write any changes to runtime stores. Handle resolution is also skipped in dry-run mode: the importer accepts handle fields without attempting to look up their target resources. Use dry-run to validate YAML structure before applying it.
Delete File-Backed Declarative Resource
POST /import/delete removes a declarative file-backed resource by resourceType and resourceKey.
{
"resourceType": "application",
"resourceKey": "my-console-app"
}
Example response:
{
"resourceType": "application",
"resourceKey": "my-console-app",
"deletedFile": "applications/my-console-app.yaml"
}
Expected Side Effects
When import runs with dryRun=false, ThunderID persists resource changes in runtime stores.
When POST /import/delete succeeds, ThunderID removes the matching declarative YAML file from config/resources.
Error Handling
Typical failures include:
- Invalid request payload (
IMP-1001). - Invalid YAML content (
IMP-1002). - Template resolution failures (
IMP-1003). - Adapter not configured for a resource type (
IMP-1004). - Internal server error (
SSE-5000).