Map API Entities to Terraform Resources
Entity Mapping
Add the x-speakeasy-entity extension to objects in your OpenAPI Specification document to include them as entities in the Terraform provider, such as managed resources. The extension value may be a single string or an array of strings if the object should be represented by multiple API entities.
As a component:
components:
schemas:
Order:
description: An order helps you make coffee
x-speakeasy-entity: Order
properties:
id:
type: integer
description: Numeric identifier of the order.
name:
type: string
description: Product name of the coffee.
price:
type: number
description: Suggested cost of the coffee.
required:
- name
- price
type: objectOr inline in a path:
paths:
/order:
post:
tags:
- Order
summary: Create a coffee order
x-speakeasy-entity-operation: Order#create
requestBody:
content:
application/json:
schema:
x-speakeasy-entity: Order
properties:
id:
type: integer
description: Numeric identifier of the order.
name:
type: string
description: Product name of the coffee.
price:
type: number
description: Suggested cost of the coffee.
required:
- name
- price
type: objectresource "yourprovider_order" "example" {
name = "Filter Blend"
price = 11.5
}Where you place the x-speakeasy-entity annotation affects the Terraform resource schema structure.
- At the top level: Properties are nested objects.
- At a lower level: Properties above the annotation are flattened.
Top Level
Pet:
x-speakeasy-entity: Order
type: object
properties:
data:
type: object
properties:
name:
type: string
# ...Results in the following resource schema and configuration:
resource "yourprovider_order" "example" {
data = {
name = "Filter Blend"
}
}Lower Level
Pet:
type: object
properties:
data:
x-speakeasy-entity: Order
type: object
properties:
name:
type: string
#...Results in the following resource schema and configuration:
resource "yourprovider_order" "example" {
name = "Filter Blend"
}Warning
Properties above the x-speakeasy-entity annotation are flattened, which
could cause conflicts. Apply the annotation carefully to align the structure
of the Terraform provider with the API’s intended interaction.
Specify Terraform Operations for API Operations
The x-speakeasy-entity-operation annotation on an API operation in the OpenAPI Specification specifies Terraform operations associated with an particular Terraform entity, such as a managed resource. In the simplest string value form, it is structured as entity#operation[#order] where:
entity: Name of the Terraform entity for the API operation, such as the name of a Terraform managed resource.operation: Associated Terraform operation, such asclose,create,delete,invoke,open,read, orupdate.order: (Optional) Ordering for API operation within the same Terraform operation, such as defining multiple API operations that should be invoked for a Terraform operation.
Managed Resource Terraform Operations
Define managed resources (sometimes called “resources”), which are associated with API resources that typically have a create, read, update, and delete (CRUD) lifecycle:
entity#create: (Required) API operation(s) for creating an instance of an API resource. Also supports API operations for immediate update during creation, if certain API resource properties are not configurable during the initial creation.entity#create,update: Alternative idempotent API operation(s) for creating and updating an instance of an API resource.
entity#read: API operation(s) for reading an instance of an API resource. Enables Terraform configuration drift detection and import support. By default, a data resource of the same entity name will also be generated.entity#updateAPI operation(s) for updating an instance, or specific properties, of an API resource. Enables in-place API resource updates rather than forcing replacement (deleting and re-creating the API resource) for Terraform configuration changes.entity#deleteAPI operation(s) for deleting an instance of an API resource.
In this example, a pet managed resource with full create, read, update, and delete lifecycle and pet data resource (due to pet#read) are generated:
paths:
/pet:
post:
description: Add a new pet to the store
x-speakeasy-entity-operation: pet#create
/pet/{id}:
parameters:
- name: id
in: path
required: true
description: Pet identifier in the store
schema:
type: integer
get:
description: Retrieve a specific pet in the store
x-speakeasy-entity-operation: pet#read
put:
description: Update a specific pet in the store
x-speakeasy-entity-operation: pet#update
delete:
description: Remove a specific pet from the store
x-speakeasy-entity-operation: pet#deleteData Resource Terraform Operations
Define data resources (sometimes called “data sources”), which are associated with API data that is useful for dynamic lookup:
entity#read: (Required) API operation(s) associated with reading data.
In this example, both pets and pet data resources are generated:
paths:
/pet:
get:
description: List all pets in the store
x-speakeasy-entity-operation: pets#read
/pet/{id}:
parameters:
- name: id
in: path
required: true
description: Pet identifier in the store
schema:
type: integer
get:
description: Retrieve a specific pet in the store
x-speakeasy-entity-operation: pet#readEphemeral Resource Terraform Operations
Define ephemeral resources , which are associated with temporary API data or concepts:
entity#open: (Required) API operation(s) associated with the Terraform ephemeral resource open lifecycle, such as fetching a temporary secret or opening a temporary network connection.entity#close: API operation(s) associated with the Terraform ephemeral resource close lifecycle, such as closing a temporary network connection.
In this example, a token ephemeral resource is generated:
paths:
/token:
get:
description: Retrieve a temporary token
x-speakeasy-entity-operation: token#openIn this example, a tunnel ephemeral resource with open and close lifecycle is generated:
paths:
/tunnel:
post:
description: Open the network tunnel
x-speakeasy-entity-operation: tunnel#open
delete:
description: Close the network tunnel
x-speakeasy-entity-operation: tunnel#closeAction Terraform Operations
Define actions , which are API operations to invoke for automations:
entity#invoke: (Required) API operation(s) associated with the Terraform action, such as starting an automation task.
In this example, a backup action is generated:
paths:
/backup:
post:
description: Create a backup
x-speakeasy-entity-operation: backup#invokeMultiple API Operations for One Resource
When multiple API operations are necessary for a single resource, use the additional entity-ordering capabilities of the x-speakeasy-entity-operation annotation.
paths:
/pet/{petId}:
get:
x-speakeasy-entity-operation: Pet#read#1
/animal:
get:
x-speakeasy-entity-operation: Pet#read#2Multiple API operations for one resource can be combined with multiple entity operations of one API operation for multiple resources as necessary.
If additional API operations have transient properties, such as an asynchronous task identifier necessary for polling, use x-speakeasy-terraform-ignore: schema to remove them from the Terraform schema.
One API Operation for Multiple Resources
When a single API operation is necessary for multiple resources, use multiple entity operation entries with the x-speakeasy-entity-operation annotation.
parameters:
- in: query
name: id
required: false
schema:
type: string
operationId: GetAnimal
x-speakeasy-entity-operation:
- Cat#read
- Dog#readOne API operation for multiple resources can be combined with the entity operation ordering of multiple API operations for one resource as necessary.
If the resource creation requires both a create and update operation where the create response includes an API assigned resource identifier, mark the update request resource identifier property as read only via x-speakeasy-param-readonly: true to ensure the property remains non-configurable in the schema.
API Operation Pagination
Define automatic API operation pagination logic, such as paginated list APIs, via the x-speakeasy-pagination extension. The generation will automatically handle paging through all responses and removing pagination properties from resource schemas that would be extraneous to Terraform configurations.
In this example, an automatically paginated Pets data resource is defined:
paths:
/pet:
get:
tags:
- pet
summary: Lists all pets
x-speakeasy-entity-operation: Pets#read
x-speakeasy-pagination:
type: offsetLimit
inputs:
- name: page
in: parameters
type: page
outputs:
results: $.resultsAPI Operation Polling
Define automatic API operation polling logic for APIs with asynchronous behaviors via the x-speakeasy-polling and x-speakeasy-entity-operation extensions in the OpenAPI Specification document. Refer to the SDK Polling documentation for additional information about configuring x-speakeasy-polling.
In this example:
/task:
post:
x-speakeasy-entity-operation: Task#create#1
/task/{id}:
get:
responses:
"200":
description: OK
content:
application/json:
schema:
type: object
properties:
name:
type: string
status:
type: string
enum:
- completed
- errored
- pending
- running
required:
- name
- status
x-speakeasy-polling:
- name: WaitForCompleted
failureCriteria:
- condition: $statusCode == 200
- condition: $response.body#/status == "errored"
successCriteria:
- condition: $statusCode == 200
- condition: $response.body#/status == "completed"
x-speakeasy-entity-operation:
- Task#read
- entityOperation: Task#create#2
options:
polling:
name: WaitForCompletedThe API operation is used for both the read operation and the second create operation, where the second create operation will use the WaitForCompleted polling method to ensure the success criteria is met before the resource logic (and therefore Terraform) continues.
There are delaySeconds, intervalSeconds, and limitCount configurations to override the x-speakeasy-polling configuration values for a specific entity operation.
In this example:
/task/{id}:
get:
x-speakeasy-polling:
- name: WaitForCompleted
failureCriteria:
- condition: $statusCode == 200
- condition: $response.body#/status == "errored"
intervalSeconds: 5
successCriteria:
- condition: $statusCode == 200
- condition: $response.body#/status == "completed"
x-speakeasy-entity-operation:
- Task#read
- entityOperation: Task#create#2
options:
polling:
name: WaitForCompleted
intervalSeconds: 10The WaitForCompleted polling method for the API operation defaults to a 5 second interval, however the create entity operation overrides to a 10 second interval.
Update Patch Semantics
Define automatic patch semantics for Terraform provider update operations via the x-speakeasy-entity-operation extension in the OpenAPI Specification document. When enabled, entity operations will only send attributes that have changed from their prior state, rather than sending the entire resource representation.
This is particularly useful for APIs that support partial updates (such as PATCH semantics) where sending unchanged fields may cause unintended side effects or where bandwidth efficiency is important.
Basic Usage
In this example:
/resource:
post:
x-speakeasy-entity-operation:
- entityOperation: Resource#create,update
options:
patch:
style: only-send-changed-attributes
operationId: create-or-update-resource
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ResourceRequest"
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/ResourceResponse"The create,update entity operation uses the only-send-changed-attributes patch style. During entity operations, the generated Terraform provider will compare each attribute against its prior state and only include attributes that have changed in the API request.
Configuration
The patch style is configured within the options section of an entity operation mapping:
x-speakeasy-entity-operation:
- entityOperation: Entity#operation
options:
patch:
style: only-send-changed-attributesWhen to Use
Use only-send-changed-attributes when:
- Your API supports partial updates (PATCH semantics) and may have side effects when unchanged fields are sent
- You want to minimize request payload size by excluding unchanged attributes
- Your API has fields where re-sending the same value triggers unwanted behavior (such as regenerating tokens or timestamps)
Manual association between Operations and Resource / Data Sources
The default behavior within Speakeasy is to automatically infer a data source from all operations that have an x-speakeasy-entity-operation: Entity#read association defined.
For some APIs, you might want the data source to use a “search” endpoint (e.g., search for an entity by name, where name is non-unique), while using a “get” operation for the resource (e.g., to find an entity by ID for state reconciliation).
In this case, use an object syntax for the x-speakeasy-entity-operation annotation to explicitly control whether an operation generates a resource, a data source, or both:
paths:
"/example":
get:
operationId: getThing
x-speakeasy-entity-operation:
terraform-datasource: null
terraform-resource: Thing#readThis syntax allows you to:
- Prevent automatic generation of a data source by setting
terraform-datasourcetonull - Prevent invocation of the operation during the resource’s Read method (“invoked as part of terraform state refresh”) by setting
terraform-resourcetonull
For example, the configuration above declares that getThing is associated with just a resource, and a data source should not be automatically generated.
Wrapping Additional API Operation Response Data
When defining multiple API operations for a single entity, an API definition may be written such that those API operation response are a flattened object. When adding those additional operations to the entity, those flattened object properties are added to the top level of the resource schema by default.
Use x-speakeasy-wrapped-attribute extension to override this behavior, which will create a wrapping attribute that contains the underlying object properties in the final resource schema.
In this example, the resource will put the second API operation response properties underneath a subconfig attribute:
paths:
/example/{id}:
parameters:
- name: id
in: path
required: true
schema:
type: string
get:
x-speakeasy-entity-operation: Example#read
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/ExampleResponse"
/example/{id}/subconfig:
parameters:
- name: id
in: path
required: true
schema:
type: string
get:
x-speakeasy-entity-operation: Example#read#2
responses:
"200":
description: OK
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/ExampleSubconfigResponse"
- x-speakeasy-wrapped-attribute: subconfigArray Response Wrapping
Terraform resources require an object-type root schema. When an API returns an array, Speakeasy automatically wraps it in an attribute (default name: data).
Default behavior:
paths:
/things:
get:
x-speakeasy-entity-operation: Things#read
responses:
"200":
description: OK
content:
application/json:
schema:
type: array
items:
x-speakeasy-entity: ThingsSince the response is type: array, Speakeasy wraps it in a data attribute for Terraform compatibility.
Access in Terraform:
data.example_things.data[0].idCustomize the wrapper name:
paths:
/things:
get:
x-speakeasy-entity-operation: Things#read
responses:
"200":
description: OK
content:
application/json:
schema:
x-speakeasy-wrapped-attribute: items
type: array
items:
x-speakeasy-entity: ThingsNow the wrapping attribute is named items instead:
data.example_things.items[0].idNote
The wrapping attribute name is a Terraform construct created by Speakeasy,
completely separate from your API’s response structure. Use
x-speakeasy-wrapped-attribute to customize it.
Resources with Soft Delete
By default, a generated managed resource uses the HTTP 404 Not Found status code on read to automatically remove the resource from the Terraform state which causes the next Terraform plan to propose recreating the resource. For resource APIs that support soft delete (grace time period before the resource is fully deleted), the x-speakeasy-soft-delete-property annotation adds a check against a read response property to also propose resource recreation.
For managed resources, any x-speakeasy-soft-delete-property attribute is omitted from the schema and state. For data resources, the attribute remains to preserve client-side filtering capabilities.
In this example, the resource will be proposed for recreation if the deleted_at property has a value:
paths:
"/example":
get:
x-speakeasy-entity-operation: Example#read
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schema/ExampleGetResponse"
components:
schemas:
ExampleGetResponse:
type: object
properties:
# ...
deleted_at:
type: string
format: date-time
x-speakeasy-soft-delete-property: trueLast updated on