1. Packages
  2. FusionAuth
  3. API Docs
  4. FusionAuthApiKey
FusionAuth v5.1.0 published on Tuesday, Oct 22, 2024 by Theo Gravity

fusionauth.FusionAuthApiKey

Explore with Pulumi AI

fusionauth logo
FusionAuth v5.1.0 published on Tuesday, Oct 22, 2024 by Theo Gravity

    # API Key

    The FusionAuth APIs are primarily secured using API keys. This API can only be accessed using an API key that is set as a keyManager. In order to retrieve, update or delete an API key, an API key with equal or greater permissions must be used. A “tenant-scoped” API key can retrieve, create, update or delete an API key for the same tenant. This page describes APIs that are used to manage API keys.

    API Key

    Example Usage

    import * as pulumi from "@pulumi/pulumi";
    import * as fusionauth from "pulumi-fusionauth";
    
    const example = new fusionauth.FusionAuthApiKey("example", {
        description: "my super secret key",
        key: "super-secret-key",
        permissionsEndpoints: [{
            "delete": true,
            endpoint: "/api/application",
            get: true,
            patch: true,
            post: true,
            put: true,
        }],
        tenantId: "94f751c5-4883-4684-a817-6b106778edec",
    });
    
    import pulumi
    import theogravity_pulumi_fusionauth as fusionauth
    
    example = fusionauth.FusionAuthApiKey("example",
        description="my super secret key",
        key="super-secret-key",
        permissions_endpoints=[fusionauth.FusionAuthApiKeyPermissionsEndpointArgs(
            delete=True,
            endpoint="/api/application",
            get=True,
            patch=True,
            post=True,
            put=True,
        )],
        tenant_id="94f751c5-4883-4684-a817-6b106778edec")
    
    package main
    
    import (
    	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    	"github.com/theogravity/pulumi-fusionauth/sdk/go/fusionauth"
    )
    
    func main() {
    	pulumi.Run(func(ctx *pulumi.Context) error {
    		_, err := fusionauth.NewFusionAuthApiKey(ctx, "example", &fusionauth.FusionAuthApiKeyArgs{
    			Description: pulumi.String("my super secret key"),
    			Key:         pulumi.String("super-secret-key"),
    			PermissionsEndpoints: fusionauth.FusionAuthApiKeyPermissionsEndpointArray{
    				&fusionauth.FusionAuthApiKeyPermissionsEndpointArgs{
    					Delete:   pulumi.Bool(true),
    					Endpoint: pulumi.String("/api/application"),
    					Get:      pulumi.Bool(true),
    					Patch:    pulumi.Bool(true),
    					Post:     pulumi.Bool(true),
    					Put:      pulumi.Bool(true),
    				},
    			},
    			TenantId: pulumi.String("94f751c5-4883-4684-a817-6b106778edec"),
    		})
    		if err != nil {
    			return err
    		}
    		return nil
    	})
    }
    
    using System.Collections.Generic;
    using System.Linq;
    using Pulumi;
    using Fusionauth = theogravity.Fusionauth;
    
    return await Deployment.RunAsync(() => 
    {
        var example = new Fusionauth.FusionAuthApiKey("example", new()
        {
            Description = "my super secret key",
            Key = "super-secret-key",
            PermissionsEndpoints = new[]
            {
                new Fusionauth.Inputs.FusionAuthApiKeyPermissionsEndpointArgs
                {
                    Delete = true,
                    Endpoint = "/api/application",
                    Get = true,
                    Patch = true,
                    Post = true,
                    Put = true,
                },
            },
            TenantId = "94f751c5-4883-4684-a817-6b106778edec",
        });
    
    });
    
    package generated_program;
    
    import com.pulumi.Context;
    import com.pulumi.Pulumi;
    import com.pulumi.core.Output;
    import com.pulumi.fusionauth.FusionAuthApiKey;
    import com.pulumi.fusionauth.FusionAuthApiKeyArgs;
    import com.pulumi.fusionauth.inputs.FusionAuthApiKeyPermissionsEndpointArgs;
    import java.util.List;
    import java.util.ArrayList;
    import java.util.Map;
    import java.io.File;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    
    public class App {
        public static void main(String[] args) {
            Pulumi.run(App::stack);
        }
    
        public static void stack(Context ctx) {
            var example = new FusionAuthApiKey("example", FusionAuthApiKeyArgs.builder()
                .description("my super secret key")
                .key("super-secret-key")
                .permissionsEndpoints(FusionAuthApiKeyPermissionsEndpointArgs.builder()
                    .delete(true)
                    .endpoint("/api/application")
                    .get(true)
                    .patch(true)
                    .post(true)
                    .put(true)
                    .build())
                .tenantId("94f751c5-4883-4684-a817-6b106778edec")
                .build());
    
        }
    }
    
    resources:
      example:
        type: fusionauth:FusionAuthApiKey
        properties:
          description: my super secret key
          key: super-secret-key
          permissionsEndpoints:
            - delete: true
              endpoint: /api/application
              get: true
              patch: true
              post: true
              put: true
          tenantId: 94f751c5-4883-4684-a817-6b106778edec
    

    Create FusionAuthApiKey Resource

    Resources are created with functions called constructors. To learn more about declaring and configuring resources, see Resources.

    Constructor syntax

    new FusionAuthApiKey(name: string, args?: FusionAuthApiKeyArgs, opts?: CustomResourceOptions);
    @overload
    def FusionAuthApiKey(resource_name: str,
                         args: Optional[FusionAuthApiKeyArgs] = None,
                         opts: Optional[ResourceOptions] = None)
    
    @overload
    def FusionAuthApiKey(resource_name: str,
                         opts: Optional[ResourceOptions] = None,
                         description: Optional[str] = None,
                         ip_access_control_list_id: Optional[str] = None,
                         key: Optional[str] = None,
                         key_id: Optional[str] = None,
                         permissions_endpoints: Optional[Sequence[FusionAuthApiKeyPermissionsEndpointArgs]] = None,
                         tenant_id: Optional[str] = None)
    func NewFusionAuthApiKey(ctx *Context, name string, args *FusionAuthApiKeyArgs, opts ...ResourceOption) (*FusionAuthApiKey, error)
    public FusionAuthApiKey(string name, FusionAuthApiKeyArgs? args = null, CustomResourceOptions? opts = null)
    public FusionAuthApiKey(String name, FusionAuthApiKeyArgs args)
    public FusionAuthApiKey(String name, FusionAuthApiKeyArgs args, CustomResourceOptions options)
    
    type: fusionauth:FusionAuthApiKey
    properties: # The arguments to resource properties.
    options: # Bag of options to control resource's behavior.
    
    

    Parameters

    name string
    The unique name of the resource.
    args FusionAuthApiKeyArgs
    The arguments to resource properties.
    opts CustomResourceOptions
    Bag of options to control resource's behavior.
    resource_name str
    The unique name of the resource.
    args FusionAuthApiKeyArgs
    The arguments to resource properties.
    opts ResourceOptions
    Bag of options to control resource's behavior.
    ctx Context
    Context object for the current deployment.
    name string
    The unique name of the resource.
    args FusionAuthApiKeyArgs
    The arguments to resource properties.
    opts ResourceOption
    Bag of options to control resource's behavior.
    name string
    The unique name of the resource.
    args FusionAuthApiKeyArgs
    The arguments to resource properties.
    opts CustomResourceOptions
    Bag of options to control resource's behavior.
    name String
    The unique name of the resource.
    args FusionAuthApiKeyArgs
    The arguments to resource properties.
    options CustomResourceOptions
    Bag of options to control resource's behavior.

    Constructor example

    The following reference example uses placeholder values for all input properties.

    var fusionAuthApiKeyResource = new Fusionauth.FusionAuthApiKey("fusionAuthApiKeyResource", new()
    {
        Description = "string",
        IpAccessControlListId = "string",
        Key = "string",
        KeyId = "string",
        PermissionsEndpoints = new[]
        {
            new Fusionauth.Inputs.FusionAuthApiKeyPermissionsEndpointArgs
            {
                Endpoint = "string",
                Delete = false,
                Get = false,
                Patch = false,
                Post = false,
                Put = false,
            },
        },
        TenantId = "string",
    });
    
    example, err := fusionauth.NewFusionAuthApiKey(ctx, "fusionAuthApiKeyResource", &fusionauth.FusionAuthApiKeyArgs{
    	Description:           pulumi.String("string"),
    	IpAccessControlListId: pulumi.String("string"),
    	Key:                   pulumi.String("string"),
    	KeyId:                 pulumi.String("string"),
    	PermissionsEndpoints: fusionauth.FusionAuthApiKeyPermissionsEndpointArray{
    		&fusionauth.FusionAuthApiKeyPermissionsEndpointArgs{
    			Endpoint: pulumi.String("string"),
    			Delete:   pulumi.Bool(false),
    			Get:      pulumi.Bool(false),
    			Patch:    pulumi.Bool(false),
    			Post:     pulumi.Bool(false),
    			Put:      pulumi.Bool(false),
    		},
    	},
    	TenantId: pulumi.String("string"),
    })
    
    var fusionAuthApiKeyResource = new FusionAuthApiKey("fusionAuthApiKeyResource", FusionAuthApiKeyArgs.builder()
        .description("string")
        .ipAccessControlListId("string")
        .key("string")
        .keyId("string")
        .permissionsEndpoints(FusionAuthApiKeyPermissionsEndpointArgs.builder()
            .endpoint("string")
            .delete(false)
            .get(false)
            .patch(false)
            .post(false)
            .put(false)
            .build())
        .tenantId("string")
        .build());
    
    fusion_auth_api_key_resource = fusionauth.FusionAuthApiKey("fusionAuthApiKeyResource",
        description="string",
        ip_access_control_list_id="string",
        key="string",
        key_id="string",
        permissions_endpoints=[{
            "endpoint": "string",
            "delete": False,
            "get": False,
            "patch": False,
            "post": False,
            "put": False,
        }],
        tenant_id="string")
    
    const fusionAuthApiKeyResource = new fusionauth.FusionAuthApiKey("fusionAuthApiKeyResource", {
        description: "string",
        ipAccessControlListId: "string",
        key: "string",
        keyId: "string",
        permissionsEndpoints: [{
            endpoint: "string",
            "delete": false,
            get: false,
            patch: false,
            post: false,
            put: false,
        }],
        tenantId: "string",
    });
    
    type: fusionauth:FusionAuthApiKey
    properties:
        description: string
        ipAccessControlListId: string
        key: string
        keyId: string
        permissionsEndpoints:
            - delete: false
              endpoint: string
              get: false
              patch: false
              post: false
              put: false
        tenantId: string
    

    FusionAuthApiKey Resource Properties

    To learn more about resource properties and how to use them, see Inputs and Outputs in the Architecture and Concepts docs.

    Inputs

    In Python, inputs that are objects can be passed either as argument classes or as dictionary literals.

    The FusionAuthApiKey resource accepts the following input properties:

    Description string
    Description of the key.
    IpAccessControlListId string
    The Id of the IP Access Control List limiting access to this API key.
    Key string
    API key string. When you create an API key the key is defaulted to a secure random value but the API key is simply a string, so you may call it super-secret-key if you’d like. However a long and random value makes a good API key in that it is unique and difficult to guess.
    KeyId string
    The Id to use for the new Form. If not specified a secure random UUID will be generated.
    PermissionsEndpoints List<theogravity.Fusionauth.Inputs.FusionAuthApiKeyPermissionsEndpoint>
    The unique Id of the private key downloaded from Apple and imported into Key Master that will be used to sign the client secret.
    TenantId string
    The unique Id of the Tenant. This value is required if the key is meant to be tenant scoped. Tenant scoped keys can only be used to access users and other tenant scoped objects for the specified tenant. This value is read-only once the key is created.
    Description string
    Description of the key.
    IpAccessControlListId string
    The Id of the IP Access Control List limiting access to this API key.
    Key string
    API key string. When you create an API key the key is defaulted to a secure random value but the API key is simply a string, so you may call it super-secret-key if you’d like. However a long and random value makes a good API key in that it is unique and difficult to guess.
    KeyId string
    The Id to use for the new Form. If not specified a secure random UUID will be generated.
    PermissionsEndpoints []FusionAuthApiKeyPermissionsEndpointArgs
    The unique Id of the private key downloaded from Apple and imported into Key Master that will be used to sign the client secret.
    TenantId string
    The unique Id of the Tenant. This value is required if the key is meant to be tenant scoped. Tenant scoped keys can only be used to access users and other tenant scoped objects for the specified tenant. This value is read-only once the key is created.
    description String
    Description of the key.
    ipAccessControlListId String
    The Id of the IP Access Control List limiting access to this API key.
    key String
    API key string. When you create an API key the key is defaulted to a secure random value but the API key is simply a string, so you may call it super-secret-key if you’d like. However a long and random value makes a good API key in that it is unique and difficult to guess.
    keyId String
    The Id to use for the new Form. If not specified a secure random UUID will be generated.
    permissionsEndpoints List<FusionAuthApiKeyPermissionsEndpoint>
    The unique Id of the private key downloaded from Apple and imported into Key Master that will be used to sign the client secret.
    tenantId String
    The unique Id of the Tenant. This value is required if the key is meant to be tenant scoped. Tenant scoped keys can only be used to access users and other tenant scoped objects for the specified tenant. This value is read-only once the key is created.
    description string
    Description of the key.
    ipAccessControlListId string
    The Id of the IP Access Control List limiting access to this API key.
    key string
    API key string. When you create an API key the key is defaulted to a secure random value but the API key is simply a string, so you may call it super-secret-key if you’d like. However a long and random value makes a good API key in that it is unique and difficult to guess.
    keyId string
    The Id to use for the new Form. If not specified a secure random UUID will be generated.
    permissionsEndpoints FusionAuthApiKeyPermissionsEndpoint[]
    The unique Id of the private key downloaded from Apple and imported into Key Master that will be used to sign the client secret.
    tenantId string
    The unique Id of the Tenant. This value is required if the key is meant to be tenant scoped. Tenant scoped keys can only be used to access users and other tenant scoped objects for the specified tenant. This value is read-only once the key is created.
    description str
    Description of the key.
    ip_access_control_list_id str
    The Id of the IP Access Control List limiting access to this API key.
    key str
    API key string. When you create an API key the key is defaulted to a secure random value but the API key is simply a string, so you may call it super-secret-key if you’d like. However a long and random value makes a good API key in that it is unique and difficult to guess.
    key_id str
    The Id to use for the new Form. If not specified a secure random UUID will be generated.
    permissions_endpoints Sequence[FusionAuthApiKeyPermissionsEndpointArgs]
    The unique Id of the private key downloaded from Apple and imported into Key Master that will be used to sign the client secret.
    tenant_id str
    The unique Id of the Tenant. This value is required if the key is meant to be tenant scoped. Tenant scoped keys can only be used to access users and other tenant scoped objects for the specified tenant. This value is read-only once the key is created.
    description String
    Description of the key.
    ipAccessControlListId String
    The Id of the IP Access Control List limiting access to this API key.
    key String
    API key string. When you create an API key the key is defaulted to a secure random value but the API key is simply a string, so you may call it super-secret-key if you’d like. However a long and random value makes a good API key in that it is unique and difficult to guess.
    keyId String
    The Id to use for the new Form. If not specified a secure random UUID will be generated.
    permissionsEndpoints List<Property Map>
    The unique Id of the private key downloaded from Apple and imported into Key Master that will be used to sign the client secret.
    tenantId String
    The unique Id of the Tenant. This value is required if the key is meant to be tenant scoped. Tenant scoped keys can only be used to access users and other tenant scoped objects for the specified tenant. This value is read-only once the key is created.

    Outputs

    All input properties are implicitly available as output properties. Additionally, the FusionAuthApiKey resource produces the following output properties:

    Id string
    The provider-assigned unique ID for this managed resource.
    Id string
    The provider-assigned unique ID for this managed resource.
    id String
    The provider-assigned unique ID for this managed resource.
    id string
    The provider-assigned unique ID for this managed resource.
    id str
    The provider-assigned unique ID for this managed resource.
    id String
    The provider-assigned unique ID for this managed resource.

    Look up Existing FusionAuthApiKey Resource

    Get an existing FusionAuthApiKey resource’s state with the given name, ID, and optional extra properties used to qualify the lookup.

    public static get(name: string, id: Input<ID>, state?: FusionAuthApiKeyState, opts?: CustomResourceOptions): FusionAuthApiKey
    @staticmethod
    def get(resource_name: str,
            id: str,
            opts: Optional[ResourceOptions] = None,
            description: Optional[str] = None,
            ip_access_control_list_id: Optional[str] = None,
            key: Optional[str] = None,
            key_id: Optional[str] = None,
            permissions_endpoints: Optional[Sequence[FusionAuthApiKeyPermissionsEndpointArgs]] = None,
            tenant_id: Optional[str] = None) -> FusionAuthApiKey
    func GetFusionAuthApiKey(ctx *Context, name string, id IDInput, state *FusionAuthApiKeyState, opts ...ResourceOption) (*FusionAuthApiKey, error)
    public static FusionAuthApiKey Get(string name, Input<string> id, FusionAuthApiKeyState? state, CustomResourceOptions? opts = null)
    public static FusionAuthApiKey get(String name, Output<String> id, FusionAuthApiKeyState state, CustomResourceOptions options)
    Resource lookup is not supported in YAML
    name
    The unique name of the resulting resource.
    id
    The unique provider ID of the resource to lookup.
    state
    Any extra arguments used during the lookup.
    opts
    A bag of options that control this resource's behavior.
    resource_name
    The unique name of the resulting resource.
    id
    The unique provider ID of the resource to lookup.
    name
    The unique name of the resulting resource.
    id
    The unique provider ID of the resource to lookup.
    state
    Any extra arguments used during the lookup.
    opts
    A bag of options that control this resource's behavior.
    name
    The unique name of the resulting resource.
    id
    The unique provider ID of the resource to lookup.
    state
    Any extra arguments used during the lookup.
    opts
    A bag of options that control this resource's behavior.
    name
    The unique name of the resulting resource.
    id
    The unique provider ID of the resource to lookup.
    state
    Any extra arguments used during the lookup.
    opts
    A bag of options that control this resource's behavior.
    The following state arguments are supported:
    Description string
    Description of the key.
    IpAccessControlListId string
    The Id of the IP Access Control List limiting access to this API key.
    Key string
    API key string. When you create an API key the key is defaulted to a secure random value but the API key is simply a string, so you may call it super-secret-key if you’d like. However a long and random value makes a good API key in that it is unique and difficult to guess.
    KeyId string
    The Id to use for the new Form. If not specified a secure random UUID will be generated.
    PermissionsEndpoints List<theogravity.Fusionauth.Inputs.FusionAuthApiKeyPermissionsEndpoint>
    The unique Id of the private key downloaded from Apple and imported into Key Master that will be used to sign the client secret.
    TenantId string
    The unique Id of the Tenant. This value is required if the key is meant to be tenant scoped. Tenant scoped keys can only be used to access users and other tenant scoped objects for the specified tenant. This value is read-only once the key is created.
    Description string
    Description of the key.
    IpAccessControlListId string
    The Id of the IP Access Control List limiting access to this API key.
    Key string
    API key string. When you create an API key the key is defaulted to a secure random value but the API key is simply a string, so you may call it super-secret-key if you’d like. However a long and random value makes a good API key in that it is unique and difficult to guess.
    KeyId string
    The Id to use for the new Form. If not specified a secure random UUID will be generated.
    PermissionsEndpoints []FusionAuthApiKeyPermissionsEndpointArgs
    The unique Id of the private key downloaded from Apple and imported into Key Master that will be used to sign the client secret.
    TenantId string
    The unique Id of the Tenant. This value is required if the key is meant to be tenant scoped. Tenant scoped keys can only be used to access users and other tenant scoped objects for the specified tenant. This value is read-only once the key is created.
    description String
    Description of the key.
    ipAccessControlListId String
    The Id of the IP Access Control List limiting access to this API key.
    key String
    API key string. When you create an API key the key is defaulted to a secure random value but the API key is simply a string, so you may call it super-secret-key if you’d like. However a long and random value makes a good API key in that it is unique and difficult to guess.
    keyId String
    The Id to use for the new Form. If not specified a secure random UUID will be generated.
    permissionsEndpoints List<FusionAuthApiKeyPermissionsEndpoint>
    The unique Id of the private key downloaded from Apple and imported into Key Master that will be used to sign the client secret.
    tenantId String
    The unique Id of the Tenant. This value is required if the key is meant to be tenant scoped. Tenant scoped keys can only be used to access users and other tenant scoped objects for the specified tenant. This value is read-only once the key is created.
    description string
    Description of the key.
    ipAccessControlListId string
    The Id of the IP Access Control List limiting access to this API key.
    key string
    API key string. When you create an API key the key is defaulted to a secure random value but the API key is simply a string, so you may call it super-secret-key if you’d like. However a long and random value makes a good API key in that it is unique and difficult to guess.
    keyId string
    The Id to use for the new Form. If not specified a secure random UUID will be generated.
    permissionsEndpoints FusionAuthApiKeyPermissionsEndpoint[]
    The unique Id of the private key downloaded from Apple and imported into Key Master that will be used to sign the client secret.
    tenantId string
    The unique Id of the Tenant. This value is required if the key is meant to be tenant scoped. Tenant scoped keys can only be used to access users and other tenant scoped objects for the specified tenant. This value is read-only once the key is created.
    description str
    Description of the key.
    ip_access_control_list_id str
    The Id of the IP Access Control List limiting access to this API key.
    key str
    API key string. When you create an API key the key is defaulted to a secure random value but the API key is simply a string, so you may call it super-secret-key if you’d like. However a long and random value makes a good API key in that it is unique and difficult to guess.
    key_id str
    The Id to use for the new Form. If not specified a secure random UUID will be generated.
    permissions_endpoints Sequence[FusionAuthApiKeyPermissionsEndpointArgs]
    The unique Id of the private key downloaded from Apple and imported into Key Master that will be used to sign the client secret.
    tenant_id str
    The unique Id of the Tenant. This value is required if the key is meant to be tenant scoped. Tenant scoped keys can only be used to access users and other tenant scoped objects for the specified tenant. This value is read-only once the key is created.
    description String
    Description of the key.
    ipAccessControlListId String
    The Id of the IP Access Control List limiting access to this API key.
    key String
    API key string. When you create an API key the key is defaulted to a secure random value but the API key is simply a string, so you may call it super-secret-key if you’d like. However a long and random value makes a good API key in that it is unique and difficult to guess.
    keyId String
    The Id to use for the new Form. If not specified a secure random UUID will be generated.
    permissionsEndpoints List<Property Map>
    The unique Id of the private key downloaded from Apple and imported into Key Master that will be used to sign the client secret.
    tenantId String
    The unique Id of the Tenant. This value is required if the key is meant to be tenant scoped. Tenant scoped keys can only be used to access users and other tenant scoped objects for the specified tenant. This value is read-only once the key is created.

    Supporting Types

    FusionAuthApiKeyPermissionsEndpoint, FusionAuthApiKeyPermissionsEndpointArgs

    Endpoint string
    Delete bool
    HTTP DELETE Verb
    Get bool
    HTTP GET Verb
    Patch bool
    HTTP PATCH Verb
    Post bool
    HTTP POST Verb
    Put bool
    HTTP PUT Verb
    Endpoint string
    Delete bool
    HTTP DELETE Verb
    Get bool
    HTTP GET Verb
    Patch bool
    HTTP PATCH Verb
    Post bool
    HTTP POST Verb
    Put bool
    HTTP PUT Verb
    endpoint String
    delete Boolean
    HTTP DELETE Verb
    get Boolean
    HTTP GET Verb
    patch Boolean
    HTTP PATCH Verb
    post Boolean
    HTTP POST Verb
    put Boolean
    HTTP PUT Verb
    endpoint string
    delete boolean
    HTTP DELETE Verb
    get boolean
    HTTP GET Verb
    patch boolean
    HTTP PATCH Verb
    post boolean
    HTTP POST Verb
    put boolean
    HTTP PUT Verb
    endpoint str
    delete bool
    HTTP DELETE Verb
    get bool
    HTTP GET Verb
    patch bool
    HTTP PATCH Verb
    post bool
    HTTP POST Verb
    put bool
    HTTP PUT Verb
    endpoint String
    delete Boolean
    HTTP DELETE Verb
    get Boolean
    HTTP GET Verb
    patch Boolean
    HTTP PATCH Verb
    post Boolean
    HTTP POST Verb
    put Boolean
    HTTP PUT Verb

    Package Details

    Repository
    fusionauth theogravity/pulumi-fusionauth
    License
    MIT
    Notes
    This Pulumi package is based on the fusionauth Terraform Provider.
    fusionauth logo
    FusionAuth v5.1.0 published on Tuesday, Oct 22, 2024 by Theo Gravity