
## Create asset

URL: https://docs.atlan.com/product/capabilities/build-apps/sdks/python/how-tos/asset-crud/create-asset

> Create any type of asset in Atlan using the Asset builder pattern with the Python SDK (pyatlan). Enrich assets with attributes before creation via POST /api/meta/entity/bulk.

# Asset: create assets programmatically

Use `Asset` (and its typed subclasses) in the Atlan Python SDK to programmatically create any type of asset using the builder pattern.

All objects in the SDK that you can create within Atlan implement the builder pattern. This allows you to progressively build-up the object you want to create. In addition, each object provides a method that takes the minimal set of required fields to create that [asset](https://docs.atlan.com/llms/platform/python/build-your-first-metadata-workflow/llms.txt).

:::tip[Each type of asset has a different containment hierarchy]
Every asset in Atlan can have slightly different parent objects in which they exist. For example, a `GlossaryTerm` can't exist outside a `Business Graph`. A `Column` can't exist outside a `Table`, `View` or `MaterializedView`; these can't exist outside a `Schema`; which can't exist outside a `Database`; which can't exist outside a `Connection`.

The minimal required fields for each asset type will therefore be slightly different.

:::warning[Creation order is important]
As a result of this containment, creation order is important. Parent objects must be created (exist) before child objects can be created.
:::
:::

## Build minimal object needed

For example, to create a glossary term you need to provide the name of the term and either the GUID or `qualifiedName` of the glossary in which to create the term:

### Java

```java showLineNumbers title="Build minimal asset necessary for creation"
GlossaryTermBuilder<?,?> termCreator = GlossaryTerm
 .creator("Example Term", // (1)
 "b4113341-251b-4adc-81fb-2420501c30e6"); // (2)
```

1. A name for the new term.
2. The GUID or `qualifiedName` of the glossary in which to create the term.

### Python

```python showLineNumbers title="Build minimal asset necessary for creation"
from pyatlan.client.atlan import AtlanClient
from pyatlan.model.assets import AtlasGlossaryTerm

client = AtlanClient()
term = AtlasGlossaryTerm.creator(
 name="Example Term", # (1)
 glossary_guid="b4113341-251b-4adc-81fb-2420501c30e6" # (2)
)
```

1. A name for the new term.
2. The GUID of the glossary in which to create the term.

### Kotlin

```kotlin showLineNumbers title="Build minimal asset necessary for creation"
val termCreator = GlossaryTerm
 .creator(
 "Example Term", // (1)
 "b4113341-251b-4adc-81fb-2420501c30e6", // (2)
 )
```

1. A name for the new term.
2. The GUID or `qualifiedName` of the glossary in which to create the term.

### Raw REST API

:::tip[Implicit in the API calls below]
There is nothing specific to do for this step when using the raw APIs—constructing the object is simply what you place in the payload of the API calls in the steps below.
:::

## Create asset from object

This `term` object will have the minimal required information for Atlan to create it. You must then actually persist the object in Atlan[^1]:

### Java

```java title="Create the asset"
GlossaryTerm term = termCreator.build(); // (1)
AssetMutationResponse response = term.save(client); // (2)
Asset created = response.getCreatedAssets().get(0); // (3)
if (created instanceof GlossaryTerm)
Asset updated = response.getUpdatedAssets().get(0); // (5)
Business Graph glossary;
if (updated instanceof Business Graph)
```

1. Before you can take actions on the builder object you've been interacting with, you need to `build()` it into a full object.
2. Then you can do operations, like `save()`, which will either:

 - create a new asset, if Atlan doesn't have a term with the same name in the same glossary
 - update an existing asset, if Atlan already has a term with the same name in the same glossary

 Because this operation will persist the asset in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

3. You can distinguish what was created or updated:

 - `getCreatedAssets()` lists assets that were created
 - `getUpdatedAssets()` lists assets that were updated

 Note that the `save()` method always returns objects of type `Asset`, though.

4. The `Asset` class is a superclass of all assets. So you need to cast to more specific types (like `GlossaryTerm`) after verifying the object that was actually returned.

5. In this example, creating the `GlossaryTerm` actually also updates the parent `Business Graph`. This is why the `response` contains generic `Asset` objects rather than specific types—any operation might side-effect a number of different assets.

6. Like with the `GlossaryTerm`, you can check and cast the generic `Asset` returned by the response into its more specific type (`Business Graph`).

### Python

```python title="Create the asset"
response = client.asset.save(term) # (1)
created = response.assets_created(asset_type=AtlasGlossaryTerm) # (2)
if created: # (3)
 term = created[0] # (4)
updated = response.assets_updated(asset_type=AtlasGlossaryTerm) # (5) 
if updated: # (6)
 term = updated[0] # (7)
```

1. Call the `save` method which will create or update the asset in atlan.

2. You can distinguish what was created or updated:

 - `assets_created(asset_type=AtlasGlossaryTerm)` returns a lists assets of the specified type that were created.
 - `assets_updated(asset_type=AtlasGlossaryTerm)` returns a lists assets of the specified type that were updated.

3. Check if the list is empty to determine if an `AtlasGlossaryTerm` was created.

4. Get the new `AtlasGlossaryTerm` that was created.

5. In this example, creating the `AtlasGlossaryTerm` actually also updates the parent `AtlasBusiness Graph`. This is why the `response` contains an `AtlasBusiness Graph`.

6. Check if the list is empty to determine if an `AtlasBusiness Graph` was updated.

7. Get the `AtlasBusiness Graph` that was updated.

### Kotlin

```kotlin title="Create the asset"
var term = termCreator.build() // (1)
val response = term.save(client) // (2)
val created = response.createdAssets[0] // (3)
if (created is GlossaryTerm)
val updated = response.updatedAssets[0] // (5)
val glossary = if (updated is Business Graph) updated else null // (6)
```

1. Before you can take actions on the builder object you've been interacting with, you need to `build()` it into a full object.
2. Then you can do operations, like `save()`, which will either:

 - create a new asset, if Atlan doesn't have a term with the same name in the same glossary
 - update an existing asset, if Atlan already has a term with the same name in the same glossary

 Because this operation will persist the asset in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

3. You can distinguish what was created or updated:

 - `getCreatedAssets()` lists assets that were created
 - `getUpdatedAssets()` lists assets that were updated

 Note that the `save()` method always returns objects of type `Asset`, though.

4. The `Asset` class is a superclass of all assets. So you need to cast to more specific types (like `GlossaryTerm`) after verifying the object that was actually returned.

5. In this example, creating the `GlossaryTerm` actually also updates the parent `Business Graph`. This is why the `response` contains generic `Asset` objects rather than specific types—any operation might side-effect a number of different assets.

6. Like with the `GlossaryTerm`, you can check and cast the generic `Asset` returned by the response into its more specific type (`Business Graph`).

### Raw REST API

```json showLineNumbers title="POST /api/meta/entity/bulk"
{
 "entities": [ // (1)
 }
 }
 ]
}
```

1. All assets must be wrapped in an `entities` array.
2. You must provide the exact type name for the asset (case-sensitive). For a term, this is `AtlasGlossaryTerm`.
3. You must provide the exact name of the asset (case-sensitive).
4. You must provide a `qualifiedName` of the asset (case-sensitive). In the case of glossary objects (like terms), this will actually be replaced in the back-end with a generated `qualifiedName`, but you must provide some value when creating the object.
5. You must also specify the parent object in which this object is contained (if any). In the case of a term, it can only exist within a glossary. So here we specify the details of the parent glossary through the `anchor` relationship (specific to glossary assets).

## (Optional) Enrich before creating

If you want to further enrich the asset before creating it, you can do this using the builder pattern:

### Java

```java title="Alternatively, further enrich the asset before creating it"
GlossaryTerm term = termCreator // (1)
 .certificateStatus(CertificateStatus.VERIFIED) // (2)
 .announcementType(AtlanAnnouncementType.INFORMATION)
 .announcementTitle("Imported")
 .announcementMessage("This term was imported from ...")
 .build(); // (3)
AssetMutationResponse response = term.save(client); // (4)
```

1. We'll create an object you can take actions on from this creator.
2. In this example, you're adding a certificate and announcement to the object.
3. To persist the enrichment back to the object, you must `build()` the builder.
4. You can call the `save()` operation against this enriched object, the same as shown earlier. Because this operation will persist the asset in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

:::warning[Assign the result back]
Remember to assign the result of the `build()` operation back to a variable! (In the example above this happens on line 5 with `GlossaryTerm term =`.)
:::

### Python

```python showLineNumbers title="Alternatively, further enrich the asset before creating it"
from pyatlan.client.atlan import AtlanClient
from pyatlan.model.assets import AtlasBusiness Graph, AtlasGlossaryTerm
from pyatlan.model.enums import AnnouncementType, CertificateStatus

client = AtlanClient()
term = AtlasGlossaryTerm.creator(
 name="Example Term",
 glossary_guid="b4113341-251b-4adc-81fb-2420501c30e6"
)
term.certificate_status = CertificateStatus.VERIFIED
announcement = Announcement(
 announcement_type=AnnouncementType.INFORMATION,
 announcement_title="Imported",
 announcement_message="This term was imported from ..",
)
term.set_announcement(announcement)
response = client.asset.save(term) # (1)
```

1. You can call the `save()` operation against this enriched object, the same as shown earlier.

### Kotlin

```kotlin title="Alternatively, further enrich the asset before creating it"
val term = termCreator // (1)
 .certificateStatus(CertificateStatus.VERIFIED) // (2)
 .announcementType(AtlanAnnouncementType.INFORMATION)
 .announcementTitle("Imported")
 .announcementMessage("This term was imported from ...")
 .build() // (3)
val response = term.save(client) // (4)
```

1. We'll create an object you can take actions on from this creator.
2. In this example, you're adding a certificate and announcement to the object.
3. To persist the enrichment back to the object, you must `build()` the builder.
4. You can call the `save()` operation against this enriched object, the same as shown earlier. Because this operation will persist the asset in Atlan, you must [provide it an `AtlanClient`](https://docs.atlan.com/llms/platform/python/set-up-sdk/llms.txt) through which to connect to the tenant.

:::warning[Assign the result back]
Remember to assign the result of the `build()` operation back to a variable! (In the example above this happens on line 6 with `val term =`.)
:::

### Raw REST API

```json showLineNumbers title="POST /api/meta/entity/bulk"
{
 "entities": [ // (1),
 "certificateStatus": "VERIFIED", // (2)
 "announcementType": "information",
 "announcementTitle": "Imported",
 "announcementMessage": "This term was imported from..."
 }
 }
 ]
}
```

1. You would still create the asset by wrapping it within the `entities` array.
2. But you can also extend the information you store on the asset. In this example, you're adding a certificate and announcement to the object when it's created.

[^1]: Why no distinction between creation and update? This has to do with how Atlan detects changes—see the [Importance of identifiers](https://docs.atlan.com/llms/platform/python/build-your-first-metadata-workflow/llms.txt) for a more detailed explanation.

---
