Repository: opsgenie/opsgenie-cloudformation-resources (language: python)

Issue:
S3 URLs in Documentation do not work
When trying to install the integration as described in the readme the command fails.
It seems either the file does not exist, or the permissions on the bucket are wrong.

```sh
aws s3 cp s3://opsgeniedownloads/cloudformation/atlassian-opsgenie-integration-v1.1.zip .                                                                                              
fatal error: An error occurred (403) when calling the HeadObject operation: Forbidden
```
It also fails with a direct API call
```sh
 aws s3api get-object --bucket opsgeniedownloads --key /cloudformation/atlassian-opsgenie-integration-v1.1.zip test.zip                                                             
An error occurred (AccessDenied) when calling the GetObject operation: Access Denied
```

Can you please update the docs to the latest versions on these bucket and ensure that it can be downloaded?
Support Cloudformation Type configuration
Hey,

currently the custom resources requires the `ApiKey` parameter to be set. While this could be filled via a CloudFormation Dynamic reference (https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/dynamic-references.html) it still needs to be specified on every call of the resource.

CloudFormation supports an account Level configuration, which would make it possible that the secret is centrally made available and configured, therefore not each user would have to have access to the secret.

You can find more details on how to do that at
https://docs.aws.amazon.com/cloudformation-cli/latest/userguide/resource-type-model.html#resource-type-howto-configuration
Which then will be configured on an account level via the following call https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudformation/set-type-configuration.html
This would then look sth like this:

```sh
aws cloudformation set-type-configuration \
    --type-name "Atlassian::Opsgenie::Integration" \
    --type RESOURCE \
    --configuration '{"OpsgenieSettings": {"Endpoint": "api.eu.opsgenie.com", "ApiKey": "{{resolve:secretsmanager:MyOpsgenieSecret:SecretString:APIKey}}"}}'
```

You can see the typeconfiguration for example in Datadogs custom resources at https://github.com/DataDog/datadog-cloudformation-resources/blob/master/datadog-dashboards-dashboard-handler/datadog-dashboards-dashboard.json#L6-L13


Discussion / hints:
![Screenshot 2022-02-08 at 08 18 23](https://user-images.githubusercontent.com/2162832/152937249-1d798ac7-556d-4096-bb4d-8073eb46f176.png)
Also in the public cloudformation registry only 1.0.0 and 1.0.1 is listed, but the docs say 1.1 is the recent version to be used 🤔 
Also as an additional note, the command as described in the README is not working either.
```sh
 aws cloudformation register-type \                                                                                                                                      
--region eu-central-1 \
--type-name "Atlassian::Opsgenie::Integration" \
--schema-handler-package "s3://opsgeniedownloads/cloudformation/atlassian-opsgenie-integration-v1.1.zip" \
--type RESOURCE

An error occurred (CFNRegistryException) when calling the RegisterType operation: Error validating schemaHandlerPackage. Check the permissions on the bucket and object in your account and try again.
```


Fix patch:
diff --git a/README.md b/README.md
index ff5e9d0..d6107f9 100644
--- a/README.md
+++ b/README.md
@@ -3,23 +3,48 @@
 
 ## Important Update
 
-*As for the June 24, we updated the SDK and our models.*
+*As for the April 8, 2022, we updated the SDK and our models.*
 
-That means if you try to update resources please be careful if rollback is enabled. 
-New version(v1.1) users will not affected of this issue
+That means if you try to update resources please be careful if rollback is enabled. New version(v2.0.0) users will not
+affected of this issue
 
-Current version : *v1.1*
+Current version : *v2.0.0*
 
-Old version: *v1.0*
+Old version: *v1.0.1*
 
-## Supported Resources
+Models have been changed. From now on, you have to set typeConfiguration via AWS CLI or AWS Console. You are not able to
+set credentials in resource models.
+
+```
+aws cloudformation set-type-configuration \
+--region $REGION \
+--type RESOURCE \
+--type-name $RESOURCE_NAME \
+--configuration-alias default \
+--configuration { "OpsgenieCredentials": { "OpsgenieApiEndpoint": "$API_ENDPOINT", "OpsgenieApiKey": "$API_KEY" }}
+```
+
+Note: To use your type configuration in contract tests, you will need to save your type configuration json file
+in `~/.cfn-cli/typeConfiguration.json`
+
+```
+{
+    "OpsgenieCredentials": {
+        "OpsgenieApiEndpoint": "$API_ENDPOINT",
+        "OpsgenieApiKey": "$API_KEY"
+    }
+}
+```
 
+https://github.com/aws-cloudformation/cloudformation-cli
+
+## Supported Resources
 
 *Link to documentation*
- 
+
 - Opsgenie User
 
-  
+
 - Opsgenie Team
 
 
@@ -33,31 +58,55 @@ Old version: *v1.0*
 
 
 - Opsgenie User resource
-```
+```shell
+wget https://opsgeniedownloads.s3.us-west-2.amazonaws.com/cloudformation/atlassian-opsgenie-user-v2.0.0.zip
+
+aws s3 cp atlassian-opsgenie-user-v2.0.0.zip s3://$BUCKET_NAME
+
 aws cloudformation register-type \
 --region us-west-2 \
 --type-name "Atlassian::Opsgenie::User" \
---schema-handler-package "s3://opsgeniedownloads/cloudformation/atlassian-opsgenie-user-v1.1.zip" \
---type RESOURCE
+--schema-handler-package "s3://$BUCKET_NAME/atlassian-opsgenie-user-v2.0.0.zip" \
+--type RESOURCE > registration_token.json
+
+aws cloudformation describe-type-registration --registration-token $REGISTRATION_TOKEN
+
+aws cloudformation set-type-default-version --arn $TYPE_VERSION_ARN
 ```
 
 - Opsgenie Team resource
-```
+```shell
+wget https://opsgeniedownloads.s3.us-west-2.amazonaws.com/cloudformation/atlassian-opsgenie-team-v2.0.0.zip
+
+aws s3 cp atlassian-opsgenie-team-v2.0.0.zip s3://$BUCKET_NAME
+
 aws cloudformation register-type \
 --region us-west-2 \
 --type-name "Atlassian::Opsgenie::Team" \
---schema-handler-package "s3://opsgeniedownloads/cloudformation/atlassian-opsgenie-team-v1.1.zip" \
---type RESOURCE
+--schema-handler-package "s3://$BUCKET_NAME/atlassian-opsgenie-team-v2.0.0.zip" \
+--type RESOURCE > registration_token.json
+
+aws cloudformation describe-type-registration --registration-token $REGISTRATION_TOKEN
+
+aws cloudformation set-type-default-version --arn $TYPE_VERSION_ARN
 ```
 
 
 - Opsgenie Integration resource
-```
+```shell
+wget https://opsgeniedownloads.s3.us-west-2.amazonaws.com/cloudformation/atlassian-opsgenie-integration-v2.0.0.zip
+
+aws s3 cp atlassian-opsgenie-integration-v2.0.0.zip s3://$BUCKET_NAME
+
 aws cloudformation register-type \
 --region us-west-2 \
 --type-name "Atlassian::Opsgenie::Integration" \
---schema-handler-package "s3://opsgeniedownloads/cloudformation/atlassian-opsgenie-integration-v1.1.zip" \
---type RESOURCE
+--schema-handler-package "s3://$BUCKET_NAME/atlassian-opsgenie-integration-v2.0.0.zip" \
+--type RESOURCE > registration_token.json
+
+aws cloudformation describe-type-registration --registration-token $REGISTRATION_TOKEN
+
+aws cloudformation set-type-default-version --arn $TYPE_VERSION_ARN
 ```
 
 
@@ -68,3 +117,11 @@ aws cloudformation register-type \
 - navigate to desired resource (such as /opsgenie_user)
 
 - run `cfn-cli submit` command 
+
+### Install using AWS Console
+
+- navigate to Cloudformation on AWS console
+- navigate to Public Extensions section
+- select Third Party Publisher
+- search for `Atlassian::Opsgenie::User` or the others
+- activate
diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml
index f3b86db..2cc5632 100644
--- a/bitbucket-pipelines.yml
+++ b/bitbucket-pipelines.yml
@@ -22,7 +22,6 @@ pipelines:
             - export RESOURCE_NAME=Atlassian::Opsgenie::Integration
             - export RESOURCE_PACKAGE=atlassian-opsgenie-integration
             - echo $BITBUCKET_STEP_OIDC_TOKEN > $(pwd)/web-identity-token
-            - ../script.sh
             - ../register-resource.sh
 
       - step:
@@ -35,6 +34,7 @@ pipelines:
             - export AWS_WEB_IDENTITY_TOKEN_FILE=$(pwd)/web-identity-token
             - export RESOURCE_NAME=Atlassian::Opsgenie::Integration
             - echo $BITBUCKET_STEP_OIDC_TOKEN > $(pwd)/web-identity-token
+            - ../script.sh
             - ../test-check.sh
 
       - step:
@@ -66,7 +66,6 @@ pipelines:
             - export RESOURCE_NAME=Atlassian::Opsgenie::Team
             - export RESOURCE_PACKAGE=atlassian-opsgenie-team
             - echo $BITBUCKET_STEP_OIDC_TOKEN > $(pwd)/web-identity-token
-            - ../script.sh
             - ../register-resource.sh
 
       - step:
@@ -79,6 +78,7 @@ pipelines:
             - export AWS_WEB_IDENTITY_TOKEN_FILE=$(pwd)/web-identity-token
             - export RESOURCE_NAME=Atlassian::Opsgenie::Team
             - echo $BITBUCKET_STEP_OIDC_TOKEN > $(pwd)/web-identity-token
+            - ../script.sh
             - ../test-check.sh
       - step:
           name: Publish Resource
@@ -109,7 +109,6 @@ pipelines:
             - export RESOURCE_NAME=Atlassian::Opsgenie::User
             - export RESOURCE_PACKAGE=atlassian-opsgenie-user
             - echo $BITBUCKET_STEP_OIDC_TOKEN > $(pwd)/web-identity-token
-            - ../script.sh
             - ../register-resource.sh
 
       - step:
@@ -122,6 +121,7 @@ pipelines:
             - export AWS_WEB_IDENTITY_TOKEN_FILE=$(pwd)/web-identity-token
             - export RESOURCE_NAME=Atlassian::Opsgenie::User
             - echo $BITBUCKET_STEP_OIDC_TOKEN > $(pwd)/web-identity-token
+            - ../user_script.sh
             - ../test-check.sh
 
       - step:
@@ -141,7 +141,7 @@ pipelines:
 
     Register-Publisher:
       - variables:
-        - name: REGION
+          - name: REGION
       - step:
           name: Build Resource and Register Resource
           oidc: true
@@ -151,8 +151,11 @@ pipelines:
             - export AWS_WEB_IDENTITY_TOKEN_FILE=$(pwd)/web-identity-token
             - echo $BITBUCKET_STEP_OIDC_TOKEN > $(pwd)/web-identity-token
             - aws cloudformation register-publisher --connection-arn $CONNECTION_ARN --accept-terms-and-conditions
+
+    #TODO add new pipeline to deregister-type along with region parameter
+
   pull-requests:
     master:
       - step:
           Build Check:
-            - mvn package
\ No newline at end of file
+            - mvn package -B
\ No newline at end of file
diff --git a/examples/opsgenie_integration/README.md b/examples/opsgenie_integration/README.md
index f0b545e..6bcb25f 100644
--- a/examples/opsgenie_integration/README.md
+++ b/examples/opsgenie_integration/README.md
@@ -9,8 +9,6 @@ This integration allows Opsgenie's incident management capabilities to your thir
 
 | Property                 	| Description                                                                                                                                                                                                         	| Required 	| Limit                                                                                                                                                       	|
 |--------------------------	|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------	|----------	|-------------------------------------------------------------------------------------------------------------------------------------------------------------	|
-| OpsgenieApiKey           	| Your Opsgenie provided API Key                                                                                                                                                                                      	| Required 	|                                                                                                                                                             	|
-| OpsgenieApiEndpoint      	| Endpoint of API according to your preferred environment                                                                                                                                                             	| Required 	| api.eu.opsgenie.com, api.opsgenie.com                                                                                                                       	|
 | Enabled                  	| This parameter is for specifying whether the integration will be enabled or not. Defaults to true                                                                                                                   	| Required 	| Boolean value defaults to true.                                                                                                                             	|
 | Name                     	| Name of the integration                                                                                                                                                                                             	| Required 	| Name must be unique for each integration.                                                                                                                   	|
 | IntegrationType          	| The API integration supported tool that is to be created. List of integrations on Opsgenie's,Integrations page                                                                                                      	| Optional 	| Can only create API integrations. Please filter by API in the list of integrations shown in your Opsgenie console to know which integrations are supported. 	|
diff --git a/examples/opsgenie_integration/stack.json b/examples/opsgenie_integration/stack.json
index 217b173..9c35fc4 100644
--- a/examples/opsgenie_integration/stack.json
+++ b/examples/opsgenie_integration/stack.json
@@ -1,36 +1,56 @@
 {
   "AWSTemplateFormatVersion": "2010-09-09",
   "Description": "Opsgenie Integration",
-  "Parameters": {
-    "OpsgenieApiKey": {
-      "Description": "Enter Opsgenie Api Key",
-      "Type": "String"
+  "Resources": {
+    "TestIntegrationTeam": {
+      "Type": "Atlassian::Opsgenie::Team",
+      "Properties": {
+        "Name": "integration-test-team",
+        "Description": "Test team to use with integration",
+        "Members": []
+      }
     },
-    "OpsgenieEndpoint": {
-      "Description": "Enter Opsgenie Api URL",
-      "Type": "String",
-      "Default": "https://api.opsgenie.com",
-      "AllowedValues": [
-        "https://api.opsgenie.com",
-        "https://api.eu.opsgenie.com",
-        "https://api.sandbox.opsgenie.com"
+    "TestIntegration": {
+      "Type": "Atlassian::Opsgenie::Integration",
+      "Properties": {
+        "IntegrationType": "API",
+        "Name": "test-cfn-integration",
+        "Enabled": true,
+        "OwnerTeamName" : "integration-test-team",
+        "AllowReadAccess": true,
+        "AllowWriteAccess": true,
+        "AllowDeleteAccess": true,
+        "AllowConfigurationAccess": false,
+        "Responders": [
+          {
+            "type": "team",
+            "name": "integration-test-team"
+          }
+        ]
+      },
+      "DependsOn": [
+        "TestIntegrationTeam"
       ]
     }
   },
-  "Resources": {
-    "IntegrationTest": {
-      "Type": "Atlassian::Opsgenie::Integration",
-      "Properties": {
-        "OpsgenieApiKey": {
-          "Ref": "OpsgenieApiKey"
-        },
-        "OpsgenieApiEndpoint": {
-          "Ref": "OpsgenieEndpoint"
-        },
-        "IntegrationType": "Auvik",
-        "Name": "test auvik integration",
-	"Enabled":true      
-	}
+  "Outputs": {
+    "TeamId": {
+      "Description": "Opsgenie TeamId",
+      "Value": {
+        "Fn::GetAtt": [
+          "TestIntegrationTeam",
+          "TeamId"
+        ]
+      }
+    },
+    "IntegrationId": {
+      "Description": "Opsgenie IntegrationId",
+      "Value": {
+        "Fn::GetAtt": [
+          "TestIntegration",
+          "IntegrationId"
+        ]
+      }
     }
   }
 }
diff --git a/examples/opsgenie_team/README.md b/examples/opsgenie_team/README.md
index a1383d1..90d35e5 100644
--- a/examples/opsgenie_team/README.md
+++ b/examples/opsgenie_team/README.md
@@ -10,8 +10,6 @@ The Team resource supports all the fields available in Opsgenie's Team entity.
 
 | Property            	| Description                                                        	| Required 	| Limit                                 	|
 |---------------------	|--------------------------------------------------------------------	|----------	|---------------------------------------	|
-| OpsgenieApiKey      	| Your Opsgenie provided API Key                                     	| Required 	|                                       	|
-| OpsgenieApiEndpoint 	| Endpoint of API according to your preferred environment            	| Required 	| api.eu.opsgenie.com, api.opsgenie.com 	|
 | Name                	| Name of the team                                                   	| Required 	| 100 chars                             	|
 | Description         	| The description of team                                            	| Optional 	| 10000 chars                           	|
 | Members             	| The users which will be added to team, and optionally their roles. 	| Optional 	|                                       	|
diff --git a/examples/opsgenie_team/stack.json b/examples/opsgenie_team/stack.json
index ded944d..845cae2 100644
--- a/examples/opsgenie_team/stack.json
+++ b/examples/opsgenie_team/stack.json
@@ -1,39 +1,23 @@
 {
   "AWSTemplateFormatVersion": "2010-09-09",
-  "Description": "Opsgenie Test Users",
-  "Parameters": {
-    "ApiKey": {
-      "Description": "Enter Opsgenie Api Key",
-      "Type": "String"
-    },
-    "ApiEndpoint": {
-      "Description": "Enter Opsgenie Api endpoint",
-      "Type": "String",
-      "Default": "https://api.opsgenie.com",
-      "AllowedValues": [
-        "https://api.opsgenie.com",
-        "https://api.eu.opsgenie.com",
-        "https://api.sandbox.opsgenie.com"
-      ]
-    }
-  },
+  "Description": "Opsgenie Team",
   "Resources": {
     "TeamA": {
       "Type": "Atlassian::Opsgenie::Team",
       "Properties": {
-        "OpsgenieApiKey": {
-          "Ref": "ApiKey"
-        },
-        "OpsgenieApiEndpoint": {
-          "Ref": "ApiEndpoint"
-        },
         "Name": "uuuii-test-team-ops",
-        "Description": "Test team with 2 user for demonstration",
-        "Members": [
-          {
-            "UserId": "04461d66-6ec6-4632-9904-f5429aec9535",
-            "Role": "user"
-          }
+        "Description": "Test team with 0 user for demonstration",
+        "Members": []
+      }
+    }
+  },
+  "Outputs": {
+    "TeamId": {
+      "Description": "Opsgenie TeamId",
+      "Value": {
+        "Fn::GetAtt": [
+          "TeamA",
+          "TeamId"
         ]
       }
     }
diff --git a/examples/opsgenie_user/README.md b/examples/opsgenie_user/README.md
index 3516660..1db267c 100644
--- a/examples/opsgenie_user/README.md
+++ b/examples/opsgenie_user/README.md
@@ -3,14 +3,12 @@
 ## Atlassian::Opsgenie::User
 
 Allows us to create user entities in Opsgenie via Amazon Cloudformation. <br>
-Uluru resource supports three configurable properties for simplicity along with the required OpsgenieApiEndpoint and OpsgenieApiKey properties.
+The resource supports three configurable properties for simplicity.
 
 ## Fields
 
 | Field               	| Description                                             	| Required 	| Limit                                                                      	|
 |---------------------	|---------------------------------------------------------	|----------	|----------------------------------------------------------------------------	|
-| OpsgenieApiKey      	| Your Opsgenie provided API Key                          	| Required 	|                                                                            	|
-| OpsgenieApiEndpoint 	| Endpoint of API according to your preferred environment 	| Required 	| api.eu.opsgenie.com, api.opsgenie.com 	|
 | Username            	| E-mail address of the user                              	| Required 	| 100 chars                                                                  	|
 | FullName            	| Name of the user                                        	| Required 	| 512 chars                                                                  	|
 | Role                	| Role of user                                            	| Required 	| Owner, Admin, User, Custom roles   	|
diff --git a/examples/opsgenie_user/stack.json b/examples/opsgenie_user/stack.json
index ed4ba00..6b51f26 100644
--- a/examples/opsgenie_user/stack.json
+++ b/examples/opsgenie_user/stack.json
@@ -1,22 +1,25 @@
 {
   "AWSTemplateFormatVersion": "2010-09-09",
   "Description": "OG user",
-  "Parameters": {
-    "OpsgenieApiKey":{
-      "Description":"Enter Opsgenie Api Key",
-      "Type":"String"
-    },
-  },
   "Resources": {
     "TestUser": {
       "Type": "Atlassian::Opsgenie::User",
       "Properties": {
-        "OpsgenieApiKey": {"Ref": "OpsgenieApiKey"},
-        "OpsgenieApiEndpoint": "https://api.opsgenie.com",
         "Username": "test-user@opsgenie.com",
         "FullName": "test user",
         "Role": "User"
       }
     }
+  },
+  "Outputs": {
+    "UserId": {
+      "Description": "Opsgenie UserId",
+      "Value": {
+        "Fn::GetAtt": [
+          "TestUser",
+          "UserId"
+        ]
+      }
+    }
   }
 }
diff --git a/integration_template.yml b/integration_template.yml
index ea18d4b..04989a7 100644
--- a/integration_template.yml
+++ b/integration_template.yml
@@ -13,11 +13,13 @@ Resources:
     Properties:
       Handler: com.atlassian.opsgenie.integration.HandlerWrapper::handleRequest
       Runtime: java8
-      CodeUri: opsgenie_integration/target/atlassian-opsgenie-integration-handler-1.0-SNAPSHOT.jar
+      CodeUri: opsgenie_integration/target/atlassian-opsgenie-integration-handler-2.0.0.jar
+      Timeout: 60
 
   TestEntrypoint:
     Type: AWS::Serverless::Function
     Properties:
       Handler: com.atlassian.opsgenie.integration.HandlerWrapper::testEntrypoint
       Runtime: java8
-      CodeUri: opsgenie_integration/target/atlassian-opsgenie-integration-handler-1.0-SNAPSHOT.jar
\ No newline at end of file
+      CodeUri: opsgenie_integration/target/atlassian-opsgenie-integration-handler-2.0.0.jar
+      Timeout: 60
\ No newline at end of file
diff --git a/opsgenie_integration/atlassian-opsgenie-integration.json b/opsgenie_integration/atlassian-opsgenie-integration.json
index 103b6ee..3404966 100644
--- a/opsgenie_integration/atlassian-opsgenie-integration.json
+++ b/opsgenie_integration/atlassian-opsgenie-integration.json
@@ -2,6 +2,14 @@
   "typeName": "Atlassian::Opsgenie::Integration",
   "description": "Opsgenie Integration Resource definition",
   "sourceUrl": "https://github.com/opsgenie/opsgenie-cloudformation-resources",
+  "typeConfiguration": {
+    "properties": {
+      "OpsgenieCredentials": {
+        "$ref": "#/definitions/OpsgenieCredentials"
+      }
+    },
+    "additionalProperties": false
+  },
   "definitions": {
     "respondersProperty": {
       "type": "object",
@@ -21,20 +29,26 @@
           "description": "Responder username, if responder type is user",
           "minLength": 1
         }
-      }
+      },
+      "additionalProperties": false
+    },
+    "OpsgenieCredentials": {
+      "description": "Credentials for the Opsgenie API",
+      "properties": {
+        "OpsgenieApiEndpoint": {
+          "type": "string",
+          "pattern": "^https:\/\/api(\\.eu|\\.sandbox|)\\.opsgenie\\.com$"
+        },
+        "OpsgenieApiKey": {
+          "type": "string",
+          "pattern": "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"
+        }
+      },
+      "type": "object",
+      "additionalProperties": false
     }
   },
   "properties": {
-    "OpsgenieApiEndpoint": {
-      "type": "string",
-      "pattern": "^https:\/\/api(\\.eu|\\.sandbox|)\\.opsgenie\\.com$",
-      "minLength": 1
-    },
-    "OpsgenieApiKey": {
-      "type": "string",
-      "pattern": "^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$",
-      "minLength": 1
-    },
     "IntegrationApiKey": {
       "type": "string",
       "minLength": 1
@@ -51,8 +65,7 @@
     "Name": {
       "type": "string",
       "pattern": "^[a-zA-Z0-9- _.]+$",
-      "description": "Integration name",
-      "minLength": 1
+      "description": "Integration name"
     },
     "IntegrationType": {
       "type": "string",
@@ -67,8 +80,7 @@
     "OwnerTeamName": {
       "type": "string",
       "pattern": "^[a-zA-Z0-9-_.]+$",
-      "description": "Name of the integration owner team.",
-      "minLength": 1
+      "description": "Name of the integration owner team."
     },
     "AllowReadAccess": {
       "type": "boolean",
@@ -98,8 +110,6 @@
     }
   },
   "required": [
-    "OpsgenieApiEndpoint",
-    "OpsgenieApiKey",
     "Enabled",
     "IntegrationType",
     "Name"
diff --git a/opsgenie_integration/overrides.json b/opsgenie_integration/overrides.json
index 348196d..18ca8b0 100644
--- a/opsgenie_integration/overrides.json
+++ b/opsgenie_integration/overrides.json
@@ -1,7 +1,5 @@
 {
   "CREATE": {
-    "/OpsgenieApiEndpoint": "",
-    "/OpsgenieApiKey": "",
     "/Name": "Test-My-cfn-integration",
     "/IntegrationType": "API",
     "/OwnerTeamName": "CFN",
@@ -19,8 +17,6 @@
     "/AllowConfigurationAccess": false
   },
   "UPDATE": {
-    "/OpsgenieApiEndpoint": "",
-    "/OpsgenieApiKey": "",
     "/Name": "Test-My-cfn-integration",
     "/IntegrationType": "API",
     "/Enabled": true,
diff --git a/opsgenie_integration/pom.xml b/opsgenie_integration/pom.xml
index 6485510..f2557e7 100644
--- a/opsgenie_integration/pom.xml
+++ b/opsgenie_integration/pom.xml
@@ -8,13 +8,13 @@
     <groupId>com.atlassian.opsgenie.integration</groupId>
     <artifactId>atlassian-opsgenie-integration-handler</artifactId>
     <name>atlassian-opsgenie-integration-handler</name>
-    <version>1.0.1</version>
+    <version>2.0.0</version>
     <packaging>jar</packaging>
 
     <parent>
         <groupId>com.atlassian.opsgenie</groupId>
         <artifactId>opsgenie-cloudformation-resources</artifactId>
-        <version>1.0.1</version>
+        <version>2.0.0</version>
     </parent>
 
     <properties>
@@ -34,7 +34,7 @@
         <dependency>
             <groupId>software.amazon.cloudformation</groupId>
             <artifactId>aws-cloudformation-rpdk-java-plugin</artifactId>
-            <version>2.0.3</version>
+            <version>2.0.12</version>
         </dependency>
     </dependencies>
     <build>
diff --git a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/CreateHandler.java b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/CreateHandler.java
index c09d8ad..94be966 100644
--- a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/CreateHandler.java
+++ b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/CreateHandler.java
@@ -1,105 +1,83 @@
 package com.atlassian.opsgenie.integration;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.integration.client.OpsgenieClient;
 import com.atlassian.opsgenie.integration.client.OpsgenieClientException;
 import com.atlassian.opsgenie.integration.model.CreateIntegrationRequest;
 import com.atlassian.opsgenie.integration.model.CreateIntegrationResponse;
 import com.atlassian.opsgenie.integration.model.OwnerTeam;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
-import java.util.Collections;
 
-public class CreateHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.integration.Helper.*;
+
+public class CreateHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-            final AmazonWebServicesClientProxy proxy,
-            final ResourceHandlerRequest<ResourceModel> request,
-            final CallbackContext callbackContext,
-            final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
         final ResourceModel model = request.getDesiredResourceState();
-        OpsgenieClient OGClient = new OpsgenieClient(model.getOpsgenieApiEndpoint(), model.getOpsgenieApiKey());
-        CreateIntegrationRequest req = new CreateIntegrationRequest();
-
-        if (model.getAllowConfigurationAccess() == null) {
-            model.setAllowConfigurationAccess(false);
-        }
-        req.setAllowConfigurationAccess(model.getAllowConfigurationAccess());
-
-        if (model.getAllowDeleteAccess() == null) {
-            model.setAllowDeleteAccess(true);
-        }
-        req.setAllowDeleteAccess(model.getAllowDeleteAccess());
-
-        if (model.getAllowReadAccess() == null) {
-            model.setAllowReadAccess(true);
-        }
-        req.setAllowReadAccess(model.getAllowReadAccess());
+        try {
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
 
-        if (model.getAllowWriteAccess() == null) {
-            model.setAllowWriteAccess(true);
-        }
-        req.setAllowWriteAccess(model.getAllowWriteAccess());
-
-        if (model.getOwnerTeamId() != null) {
-            OwnerTeam ownerTeam = new OwnerTeam();
-            ownerTeam.setId(model.getOwnerTeamId());
-            req.setOwnerTeam(ownerTeam);
-        } else if (model.getOwnerTeamName() != null) {
-            OwnerTeam ownerTeam = new OwnerTeam();
-            ownerTeam.setName(model.getOwnerTeamName());
-            ownerTeam.setId(null);
-            req.setOwnerTeam(ownerTeam);
-        }
-        req.setName(model.getName());
+            CreateIntegrationRequest createIntegrationRequest = new CreateIntegrationRequest();
 
-        if (model.getResponders() != null) {
-            if (model.getResponders().size() > 0) {
-                req.setRespondersPropertyList(model.getResponders());
+            if (model.getAllowConfigurationAccess() == null) {
+                model.setAllowConfigurationAccess(false);
             }
-        }
-        if (model.getEnabled() == null) {
-            model.setEnabled(true);
-        }
+            createIntegrationRequest.setAllowConfigurationAccess(model.getAllowConfigurationAccess());
 
-        req.setType(model.getIntegrationType());
+            if (model.getAllowDeleteAccess() == null) {
+                model.setAllowDeleteAccess(true);
+            }
+            createIntegrationRequest.setAllowDeleteAccess(model.getAllowDeleteAccess());
 
-        req.setEnabled(model.getEnabled());
+            if (model.getAllowReadAccess() == null) {
+                model.setAllowReadAccess(true);
+            }
+            createIntegrationRequest.setAllowReadAccess(model.getAllowReadAccess());
 
-        try {
-            logger.log("[CREATE] Request data: " + req.toString());
-            if(model.getIntegrationId()!=null && !model.getIntegrationId().equals("")){
-                throw new OpsgenieClientException("Invalid request",400);
+            if (model.getAllowWriteAccess() == null) {
+                model.setAllowWriteAccess(true);
             }
-            CreateIntegrationResponse resp = OGClient.CreateIntegration(req);
-            model.setIntegrationId(resp.getData().getId());
-            model.setIntegrationApiKey(resp.getData().getApiKey());
-        } catch (OpsgenieClientException e) {
-            logger.log(e.getMessage());
-            HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
-            if (e.getCode() == 422) {
-                errorCode = HandlerErrorCode.AlreadyExists;
+            createIntegrationRequest.setAllowWriteAccess(model.getAllowWriteAccess());
+
+            if (model.getOwnerTeamId() != null) {
+                OwnerTeam ownerTeam = new OwnerTeam();
+                ownerTeam.setId(model.getOwnerTeamId());
+                createIntegrationRequest.setOwnerTeam(ownerTeam);
+            } else if (model.getOwnerTeamName() != null) {
+                OwnerTeam ownerTeam = new OwnerTeam();
+                ownerTeam.setName(model.getOwnerTeamName());
+                ownerTeam.setId(null);
+                createIntegrationRequest.setOwnerTeam(ownerTeam);
             }
-            if (e.getCode() == 429) {
-                errorCode = HandlerErrorCode.Throttling;
+            createIntegrationRequest.setName(model.getName());
+
+            if (model.getResponders() != null) {
+                if (model.getResponders()
+                         .size() > 0) {
+                    createIntegrationRequest.setRespondersPropertyList(model.getResponders());
+                }
             }
-            if (e.getCode() == 400) {
-                errorCode = HandlerErrorCode.InvalidRequest;
+            if (model.getEnabled() == null) {
+                model.setEnabled(true);
             }
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(errorCode)
-                    .message(e.getMessage())
-                    .status(OperationStatus.FAILED)
-                    .build();
+
+            createIntegrationRequest.setType(model.getIntegrationType());
+
+            createIntegrationRequest.setEnabled(model.getEnabled());
+
+            CreateIntegrationResponse createIntegrationResponse = OGClient.CreateIntegration(createIntegrationRequest);
+            model.setIntegrationId(createIntegrationResponse.getData()
+                                                            .getId());
+            model.setIntegrationApiKey(createIntegrationResponse.getData()
+                                                                .getApiKey());
+        } catch (OpsgenieClientException e) {
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
         } catch (IOException e) {
-            logger.log(e.getMessage());
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(HandlerErrorCode.InternalFailure)
-                    .message(e.getMessage())
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetInternalFailureResponse(e.getMessage());
         }
 
         logger.log("[CREATE] " + model.getIntegrationId());
diff --git a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/DeleteHandler.java b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/DeleteHandler.java
index 9aebd42..e3b56d0 100644
--- a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/DeleteHandler.java
+++ b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/DeleteHandler.java
@@ -1,46 +1,38 @@
 package com.atlassian.opsgenie.integration;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.integration.client.OpsgenieClient;
 import com.atlassian.opsgenie.integration.client.OpsgenieClientException;
+import org.apache.commons.lang3.StringUtils;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
 
-public class DeleteHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.integration.Helper.*;
+
+public class DeleteHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-        final AmazonWebServicesClientProxy proxy,
-        final ResourceHandlerRequest<ResourceModel> request,
-        final CallbackContext callbackContext,
-        final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
         final ResourceModel model = request.getDesiredResourceState();
-        OpsgenieClient OGClient = new OpsgenieClient(model.getOpsgenieApiEndpoint(),model.getOpsgenieApiKey());
-
         try {
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
+            if (StringUtils.isEmpty(model.getIntegrationId())) {
+                return GetServiceFailureResponse(404, "IntegrationId must be provided.");
+            }
+
             OGClient.DeleteIntegration(model.getIntegrationId());
-        } catch (IOException e) {
-            logger.log(e.getMessage());
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .resourceModel(model)
-                    .status(OperationStatus.FAILED)
-                    .build();
+
         } catch (OpsgenieClientException e) {
-            logger.log(e.getMessage());
-            HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
-            if (e.getCode() == 404) {
-                errorCode = HandlerErrorCode.NotFound;
-            }
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(errorCode)
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
+        } catch (IOException e) {
+            return GetInternalFailureResponse(e.getMessage());
         }
 
         logger.log("[DELETE] " + model.getIntegrationId());
         return ProgressEvent.<ResourceModel, CallbackContext>builder()
-            .status(OperationStatus.SUCCESS)
-            .build();
+                            .status(OperationStatus.SUCCESS)
+                            .build();
     }
 }
diff --git a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/Helper.java b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/Helper.java
new file mode 100644
index 0000000..d2df7e2
--- /dev/null
+++ b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/Helper.java
@@ -0,0 +1,64 @@
+package com.atlassian.opsgenie.integration;
+
+import com.atlassian.opsgenie.integration.client.OpsgenieClient;
+import com.atlassian.opsgenie.integration.client.OpsgenieClientException;
+import org.apache.commons.lang3.StringUtils;
+import software.amazon.cloudformation.proxy.HandlerErrorCode;
+import software.amazon.cloudformation.proxy.OperationStatus;
+import software.amazon.cloudformation.proxy.ProgressEvent;
+
+/**
+ * @author Furkan Yildiz
+ * @created 7.04.2022
+ */
+public class Helper {
+
+    public static OpsgenieClient CreateOGClient(TypeConfigurationModel typeConfiguration) throws OpsgenieClientException {
+        String opsgenieApiEndpoint = null;
+        String opsgenieApiKey = null;
+
+        if (typeConfiguration != null && typeConfiguration.getOpsgenieCredentials() != null) {
+            opsgenieApiEndpoint = typeConfiguration.getOpsgenieCredentials()
+                                                   .getOpsgenieApiEndpoint();
+            opsgenieApiKey = typeConfiguration.getOpsgenieCredentials()
+                                              .getOpsgenieApiKey();
+        }
+
+        if (StringUtils.isEmpty(opsgenieApiEndpoint) || StringUtils.isEmpty(opsgenieApiKey)) {
+            throw new OpsgenieClientException("OpsgenieApiEndpoint and OpsgenieApiKey must be provided in TypeConfiguration.", 401);
+        }
+
+        return new OpsgenieClient(opsgenieApiEndpoint, opsgenieApiKey);
+    }
+
+    public static ProgressEvent<ResourceModel, CallbackContext> GetInternalFailureResponse(String message) {
+        return ProgressEvent.<ResourceModel, CallbackContext>builder()
+                            .errorCode(HandlerErrorCode.InternalFailure)
+                            .message(message)
+                            .status(OperationStatus.FAILED)
+                            .build();
+    }
+
+    public static ProgressEvent<ResourceModel, CallbackContext> GetServiceFailureResponse(int responseCode, String message) {
+        HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
+        if (responseCode == 400) {
+            errorCode = HandlerErrorCode.InvalidRequest;
+        } else if (responseCode == 401) {
+            errorCode = HandlerErrorCode.InvalidCredentials;
+        } else if (responseCode == 403) {
+            errorCode = HandlerErrorCode.AccessDenied;
+        } else if (responseCode == 404) {
+            errorCode = HandlerErrorCode.NotFound;
+        } else if (responseCode == 409) {
+            errorCode = HandlerErrorCode.AlreadyExists;
+        } else if (responseCode == 429) {
+            errorCode = HandlerErrorCode.Throttling;
+        }
+        return ProgressEvent.<ResourceModel, CallbackContext>builder()
+                            .errorCode(errorCode)
+                            .message(message)
+                            .status(OperationStatus.FAILED)
+                            .build();
+    }
+
+}
diff --git a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/ListHandler.java b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/ListHandler.java
index cf8e148..5b0b0ed 100644
--- a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/ListHandler.java
+++ b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/ListHandler.java
@@ -1,55 +1,41 @@
 package com.atlassian.opsgenie.integration;
 
-import software.amazon.cloudformation.proxy.*;
-import com.atlassian.opsgenie.integration.model.ListIntegrationResponse;
 import com.atlassian.opsgenie.integration.client.OpsgenieClient;
 import com.atlassian.opsgenie.integration.client.OpsgenieClientException;
+import com.atlassian.opsgenie.integration.model.ListIntegrationResponse;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
-public class ListHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.integration.Helper.*;
+
+public class ListHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-            final AmazonWebServicesClientProxy proxy,
-            final ResourceHandlerRequest<ResourceModel> request,
-            final CallbackContext callbackContext,
-            final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
         final List<ResourceModel> models = new ArrayList<>();
-
-        OpsgenieClient OGClient = new OpsgenieClient(request.getDesiredResourceState().getOpsgenieApiEndpoint(), request.getDesiredResourceState().getOpsgenieApiKey());
-
+        final ResourceModel model = request.getDesiredResourceState();
         try {
-            ListIntegrationResponse resp = OGClient.ListIntegrations();
-            logger.log(resp.toString());
-            resp.getData().stream().forEach(model -> {
-                ResourceModel resourceModel = new ResourceModel();
-                resourceModel.setName(model.getName());
-                resourceModel.setIntegrationType(model.getType());
-                resourceModel.setIntegrationId(model.getId());
-                resourceModel.setOpsgenieApiEndpoint(request.getDesiredResourceState().getOpsgenieApiEndpoint());
-                resourceModel.setOpsgenieApiKey(request.getDesiredResourceState().getOpsgenieApiKey());
-                models.add(resourceModel);
-            });
-        } catch (IOException e) {
-            logger.log(e.getMessage());
-            e.printStackTrace();
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .status(OperationStatus.FAILED)
-                    .build();
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
+
+            ListIntegrationResponse listIntegrationResponse = OGClient.ListIntegrations();
+            listIntegrationResponse.getData()
+                                   .stream()
+                                   .forEach(dataModel -> {
+                                       ResourceModel resourceModel = new ResourceModel();
+                                       resourceModel.setName(dataModel.getName());
+                                       resourceModel.setIntegrationType(dataModel.getType());
+                                       resourceModel.setIntegrationId(dataModel.getId());
+                                       models.add(resourceModel);
+                                   });
         } catch (OpsgenieClientException e) {
-            logger.log(e.getMessage());
-            HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
-            if (e.getCode() == 404) {
-                errorCode = HandlerErrorCode.NotFound;
-            }
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(errorCode)
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
+        } catch (IOException e) {
+            return GetInternalFailureResponse(e.getMessage());
         }
 
         return ProgressEvent.<ResourceModel, CallbackContext>builder()
diff --git a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/ReadHandler.java b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/ReadHandler.java
index 02b721d..ca2a349 100644
--- a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/ReadHandler.java
+++ b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/ReadHandler.java
@@ -1,60 +1,58 @@
 package com.atlassian.opsgenie.integration;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.integration.client.OpsgenieClient;
 import com.atlassian.opsgenie.integration.client.OpsgenieClientException;
 import com.atlassian.opsgenie.integration.model.GetIntegrationResponse;
+import org.apache.commons.lang3.StringUtils;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
-public class ReadHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.integration.Helper.*;
+
+public class ReadHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-            final AmazonWebServicesClientProxy proxy,
-            final ResourceHandlerRequest<ResourceModel> request,
-            final CallbackContext callbackContext,
-            final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
+        final List<ResourceModel> models = new ArrayList<>();
         final ResourceModel model = request.getDesiredResourceState();
-
-        OpsgenieClient OGClient = new OpsgenieClient(model.getOpsgenieApiEndpoint(), model.getOpsgenieApiKey());
         try {
-            GetIntegrationResponse resp = OGClient.GetIntegration(model.getIntegrationId());
-            model.setAllowWriteAccess(resp.getData().isAllowWriteAccess());
-            model.setAllowReadAccess(resp.getData().isAllowReadAccess());
-            model.setAllowDeleteAccess(resp.getData().isAllowDeleteAccess());
-            model.setAllowConfigurationAccess(resp.getData().isAllowConfigurationAccess());
-            model.setEnabled(resp.getData().isEnabled());
-            if (resp.getData().getOwnerTeam() != null) {
-                model.setOwnerTeamId(resp.getData().getOwnerTeam().getId());
-                model.setOwnerTeamName(resp.getData().getOwnerTeam().getName());
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
+            if (StringUtils.isEmpty(model.getIntegrationId())) {
+                return GetServiceFailureResponse(404, "IntegrationId must be provided.");
             }
-            model.setResponders(resp.getData().getRespondersPropertyList());
 
-
-        } catch (OpsgenieClientException e) {
-            HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
-            logger.log(e.getMessage());
-            e.printStackTrace();
-            if (e.getCode() == 429) {
-                errorCode = HandlerErrorCode.Throttling;
-            }
-            if (e.getCode() == 404) {
-                errorCode = HandlerErrorCode.NotFound;
+            GetIntegrationResponse getIntegrationResponse = OGClient.GetIntegration(model.getIntegrationId());
+            model.setAllowWriteAccess(getIntegrationResponse.getData()
+                                                            .isAllowWriteAccess());
+            model.setAllowReadAccess(getIntegrationResponse.getData()
+                                                           .isAllowReadAccess());
+            model.setAllowDeleteAccess(getIntegrationResponse.getData()
+                                                             .isAllowDeleteAccess());
+            model.setAllowConfigurationAccess(getIntegrationResponse.getData()
+                                                                    .isAllowConfigurationAccess());
+            model.setEnabled(getIntegrationResponse.getData()
+                                                   .isEnabled());
+            if (getIntegrationResponse.getData()
+                                      .getOwnerTeam() != null) {
+                model.setOwnerTeamId(getIntegrationResponse.getData()
+                                                           .getOwnerTeam()
+                                                           .getId());
+                model.setOwnerTeamName(getIntegrationResponse.getData()
+                                                             .getOwnerTeam()
+                                                             .getName());
             }
+            model.setResponders(getIntegrationResponse.getData()
+                                                      .getRespondersPropertyList());
 
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .message(e.getMessage())
-                    .errorCode(errorCode)
-                    .status(OperationStatus.FAILED)
-                    .build();
+        } catch (OpsgenieClientException e) {
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
         } catch (IOException e) {
-            e.printStackTrace();
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(HandlerErrorCode.InternalFailure)
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetInternalFailureResponse(e.getMessage());
         }
 
         logger.log("[READ] " + model.getIntegrationId());
diff --git a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/UpdateHandler.java b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/UpdateHandler.java
index 0ca530d..9482342 100644
--- a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/UpdateHandler.java
+++ b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/UpdateHandler.java
@@ -1,71 +1,88 @@
 package com.atlassian.opsgenie.integration;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.integration.client.OpsgenieClient;
 import com.atlassian.opsgenie.integration.client.OpsgenieClientException;
-import com.atlassian.opsgenie.integration.model.*;
+import com.atlassian.opsgenie.integration.model.GetIntegrationResponse;
+import com.atlassian.opsgenie.integration.model.OwnerTeam;
+import com.atlassian.opsgenie.integration.model.UpdateIntegrationRequest;
+import org.apache.commons.lang3.StringUtils;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
-public class UpdateHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.integration.Helper.*;
+
+public class UpdateHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-            final AmazonWebServicesClientProxy proxy,
-            final ResourceHandlerRequest<ResourceModel> request,
-            final CallbackContext callbackContext,
-            final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
+        final List<ResourceModel> models = new ArrayList<>();
         final ResourceModel model = request.getDesiredResourceState();
+        try {
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
+            if (StringUtils.isEmpty(model.getIntegrationId())) {
+                return GetServiceFailureResponse(404, "IntegrationId must be provided.");
+            }
 
-        OpsgenieClient OGClient = new OpsgenieClient(model.getOpsgenieApiEndpoint(), model.getOpsgenieApiKey());
-        UpdateIntegrationRequest req = new UpdateIntegrationRequest();
-
-        model.setIntegrationApiKey(request.getPreviousResourceState().getIntegrationApiKey());
-        if (model.getOwnerTeamId() != null) {
-            OwnerTeam ownerTeam = new OwnerTeam();
-            ownerTeam.setId(model.getOwnerTeamId());
-            req.setOwnerTeam(ownerTeam);
-        } else if (model.getOwnerTeamName() != null) {
-            OwnerTeam ownerTeam = new OwnerTeam();
-            ownerTeam.setName(model.getOwnerTeamName());
-            req.setOwnerTeam(ownerTeam);
-        }
-        req.setName(model.getName());
-        req.setType(model.getIntegrationType());
-        req.setRespondersPropertyList(model.getResponders());
-        req.setId(model.getIntegrationId());
-        req.setEnabled(model.getEnabled());
+            GetIntegrationResponse getIntegrationResponse = OGClient.GetIntegration(model.getIntegrationId());
+            UpdateIntegrationRequest updateIntegrationRequest = new UpdateIntegrationRequest();
 
-        try {
-            OGClient.UpdateIntegration(req);
+            updateIntegrationRequest.setEnabled(getIntegrationResponse.getData()
+                                                                      .isEnabled());
+            updateIntegrationRequest.setId(getIntegrationResponse.getData()
+                                                                 .getId());
+            updateIntegrationRequest.setOwnerTeam(getIntegrationResponse.getData()
+                                                                        .getOwnerTeam());
+            updateIntegrationRequest.setName(getIntegrationResponse.getData()
+                                                                   .getName());
+            updateIntegrationRequest.setType(getIntegrationResponse.getData()
+                                                                   .getType());
+            updateIntegrationRequest.setIgnoreRespondersFromPayload(getIntegrationResponse.getData()
+                                                                                          .isIgnoreRespondersFromPayload());
+            updateIntegrationRequest.setIgnoreTeamsFromPayload(getIntegrationResponse.getData()
+                                                                                     .isIgnoreTeamsFromPayload());
+            updateIntegrationRequest.setRespondersPropertyList(getIntegrationResponse.getData()
+                                                                                     .getRespondersPropertyList());
+            updateIntegrationRequest.setSuppressNotifications(getIntegrationResponse.getData()
+                                                                                    .isSuppressNotifications());
 
-        } catch (OpsgenieClientException e) {
-            logger.log(e.getMessage()+e.getCode());
-            HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
-            if (e.getCode() == 429) {
-                errorCode = HandlerErrorCode.Throttling;
+            updateIntegrationRequest.setId(model.getIntegrationId());
+
+            if (model.getOwnerTeamId() != null) {
+                OwnerTeam ownerTeam = new OwnerTeam();
+                ownerTeam.setId(model.getOwnerTeamId());
+                updateIntegrationRequest.setOwnerTeam(ownerTeam);
+            } else if (model.getOwnerTeamName() != null) {
+                OwnerTeam ownerTeam = new OwnerTeam();
+                ownerTeam.setName(model.getOwnerTeamName());
+                updateIntegrationRequest.setOwnerTeam(ownerTeam);
+            }
+            if (model.getName() != null) {
+                updateIntegrationRequest.setName(model.getName());
             }
-            if (e.getCode() == 404 || e.getCode() == 422 || e.getCode() == 403) {
-                errorCode = HandlerErrorCode.NotFound;
+
+            if (model.getIntegrationType() != null) {
+                updateIntegrationRequest.setType(model.getIntegrationType());
             }
 
-            if (e.getCode() == 409 ) {
-                errorCode = HandlerErrorCode.ResourceConflict;
+            if (model.getResponders() != null) {
+                updateIntegrationRequest.setRespondersPropertyList(model.getResponders());
             }
 
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(errorCode)
-                    .message(e.getMessage())
-                    .status(OperationStatus.FAILED)
-                    .build();
+            if (model.getEnabled() != null) {
+                updateIntegrationRequest.setEnabled(model.getEnabled());
+            }
+
+            OGClient.UpdateIntegration(updateIntegrationRequest);
+
+        } catch (OpsgenieClientException e) {
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
         } catch (IOException e) {
-            logger.log(e.getMessage());
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .message(e.getMessage())
-                    .errorCode(HandlerErrorCode.InternalFailure)
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetInternalFailureResponse(e.getMessage());
         }
 
         logger.log("[UPDATE] " + model.getIntegrationId());
diff --git a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/client/OpsgenieClient.java b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/client/OpsgenieClient.java
index 41ba7e1..c2cdafb 100644
--- a/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/client/OpsgenieClient.java
+++ b/opsgenie_integration/src/main/java/com/atlassian/opsgenie/integration/client/OpsgenieClient.java
@@ -1,15 +1,10 @@
 package com.atlassian.opsgenie.integration.client;
 
-import com.atlassian.opsgenie.integration.model.CreateIntegrationRequest;
-import com.atlassian.opsgenie.integration.model.CreateIntegrationResponse;
-import com.atlassian.opsgenie.integration.model.GetIntegrationResponse;
-import com.atlassian.opsgenie.integration.model.ListIntegrationResponse;
-import com.atlassian.opsgenie.integration.model.UpdateIntegrationRequest;
+import com.atlassian.opsgenie.integration.model.*;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import okhttp3.*;
-import okhttp3.Request;
 
 import java.io.IOException;
 
@@ -27,11 +22,14 @@ public OpsgenieClient(String endpoint, String apiKey) {
     }
 
     private String execute(Request request) throws IOException, OpsgenieClientException {
-        Response response = this.httpClient.newCall(request).execute();
+        Response response = this.httpClient.newCall(request)
+                                           .execute();
         if (!(response.code() >= 200 && response.code() <= 299)) {
-            throw new OpsgenieClientException(response.body().string(), response.code());
+            throw new OpsgenieClientException(response.body()
+                                                      .string(), response.code());
         }
-        return response.body().string();
+        return response.body()
+                       .string();
 
     }
 
@@ -52,7 +50,7 @@ public CreateIntegrationResponse CreateIntegration(CreateIntegrationRequest req)
 
     public void DeleteIntegration(String Id) throws IOException, OpsgenieClientException {
         Request request = new Request.Builder()
-                .url(this.endpoint + "/v2/integrations/" + Id + "?apiKey=" + this.apiKey)
+                .url(this.endpoint + "/v2/integrations/" + Id)
                 .addHeader("Authorization", "GenieKey " + this.apiKey)
                 .addHeader("User-Agent", userAgent)
                 .delete()
@@ -71,14 +69,13 @@ public void UpdateIntegration(UpdateIntegrationRequest req) throws IOException,
                 .addHeader("User-Agent", userAgent)
                 .build();
         execute(request);
-
     }
 
     public GetIntegrationResponse GetIntegration(String Id) throws IOException, OpsgenieClientException {
         ObjectMapper objectMapper = new ObjectMapper();
         objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
         Request request = new Request.Builder()
-                .url(this.endpoint + "/v2/integrations/" + Id + "?apiKey=" + this.apiKey)
+                .url(this.endpoint + "/v2/integrations/" + Id)
                 .get()
                 .addHeader("Authorization", "GenieKey " + this.apiKey)
                 .addHeader("User-Agent", userAgent)
@@ -91,7 +88,7 @@ public ListIntegrationResponse ListIntegrations() throws IOException, OpsgenieCl
         ObjectMapper objectMapper = new ObjectMapper();
         objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
         Request request = new Request.Builder()
-                .url(this.endpoint + "/v2/integrations?apiKey=" + this.apiKey)
+                .url(this.endpoint + "/v2/integrations")
                 .get()
                 .addHeader("Authorization", "GenieKey " + this.apiKey)
                 .addHeader("User-Agent", userAgent)
diff --git a/opsgenie_team/atlassian-opsgenie-team.json b/opsgenie_team/atlassian-opsgenie-team.json
index 060888d..f70ea2f 100644
--- a/opsgenie_team/atlassian-opsgenie-team.json
+++ b/opsgenie_team/atlassian-opsgenie-team.json
@@ -2,6 +2,14 @@
   "typeName": "Atlassian::Opsgenie::Team",
   "description": "Opsgenie Team resource schema",
   "sourceUrl": "https://github.com/opsgenie/opsgenie-cloudformation-resources",
+  "typeConfiguration": {
+    "properties": {
+      "OpsgenieCredentials": {
+        "$ref": "#/definitions/OpsgenieCredentials"
+      }
+    },
+    "additionalProperties": false
+  },
   "definitions": {
     "Member": {
       "type": "object",
@@ -22,7 +30,23 @@
           "type": "string",
           "pattern": "^[a-zA-Z0-9-_.]+$"
         }
-      }
+      },
+      "additionalProperties": false
+    },
+    "OpsgenieCredentials": {
+      "description": "Credentials for the Opsgenie API",
+      "properties": {
+        "OpsgenieApiEndpoint": {
+          "type": "string",
+          "pattern": "^https:\/\/api(\\.eu|\\.sandbox|)\\.opsgenie\\.com$"
+        },
+        "OpsgenieApiKey": {
+          "type": "string",
+          "pattern": "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"
+        }
+      },
+      "type": "object",
+      "additionalProperties": false
     }
   },
   "properties": {
@@ -39,9 +63,7 @@
     "Description": {
       "description": "Team description",
       "type": "string",
-      "minLength": 1,
-      "pattern": "^[a-zA-Z0-9- _.]+$",
-      "maxLength": 100
+      "pattern": "^[a-zA-Z0-9- _.]+$"
     },
     "Members": {
       "description": "Array of members",
@@ -49,16 +71,6 @@
       "items": {
         "$ref": "#/definitions/Member"
       }
-    },
-    "OpsgenieApiKey": {
-      "description": "Api Key",
-      "type": "string",
-      "pattern": "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"
-    },
-    "OpsgenieApiEndpoint": {
-      "description": "Api endpoint",
-      "type": "string",
-      "pattern": "^https:\/\/api(\\.eu|\\.sandbox|)\\.opsgenie\\.com$"
     }
   },
   "required": [
diff --git a/opsgenie_team/overrides.json b/opsgenie_team/overrides.json
index a412799..5fb4cc3 100644
--- a/opsgenie_team/overrides.json
+++ b/opsgenie_team/overrides.json
@@ -1,7 +1,12 @@
 {
   "CREATE": {
-    "/OpsgenieApiEndpoint": "",
-    "/OpsgenieApiKey": "",
-    "/Members": []
+    "/Members": [],
+    "/Name": "Test-CFN-Team",
+    "/Description": "Test cfn team description"
+  },
+  "UPDATE": {
+    "/Members": [],
+    "/Name": "Test-CFN-Team",
+    "/Description": "Test cfn team description"
   }
 }
\ No newline at end of file
diff --git a/opsgenie_team/pom.xml b/opsgenie_team/pom.xml
index 5895c1c..e5d8549 100644
--- a/opsgenie_team/pom.xml
+++ b/opsgenie_team/pom.xml
@@ -9,13 +9,13 @@
     <parent>
         <groupId>com.atlassian.opsgenie</groupId>
         <artifactId>opsgenie-cloudformation-resources</artifactId>
-        <version>1.0.1</version>
+        <version>2.0.0</version>
     </parent>
 
     <groupId>com.atlassian.opsgenie.team</groupId>
     <artifactId>atlassian-opsgenie-team-handler</artifactId>
     <name>atlassian-opsgenie-team-handler</name>
-    <version>1.0.1</version>
+    <version>2.0.0</version>
     <packaging>jar</packaging>
 
     <properties>
@@ -29,7 +29,7 @@
         <dependency>
             <groupId>software.amazon.cloudformation</groupId>
             <artifactId>aws-cloudformation-rpdk-java-plugin</artifactId>
-            <version>2.0.3</version>
+            <version>2.0.12</version>
         </dependency>
     </dependencies>
 
diff --git a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/CreateHandler.java b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/CreateHandler.java
index ae59031..e2e7e65 100644
--- a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/CreateHandler.java
+++ b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/CreateHandler.java
@@ -1,107 +1,65 @@
 package com.atlassian.opsgenie.team;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.team.client.OpsgenieClient;
 import com.atlassian.opsgenie.team.client.OpsgenieClientException;
 import com.atlassian.opsgenie.team.model.CreateTeamRequest;
 import com.atlassian.opsgenie.team.model.CreateTeamResponse;
 import com.atlassian.opsgenie.team.model.MemberModel;
 import com.atlassian.opsgenie.team.model.UserModel;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
-public class CreateHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.team.Helper.*;
+
+public class CreateHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-            final AmazonWebServicesClientProxy proxy,
-            final ResourceHandlerRequest<ResourceModel> request,
-            final CallbackContext callbackContext,
-            final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
         final ResourceModel model = request.getDesiredResourceState();
-        CreateTeamResponse createTeamResponse;
-
-        // TODO : put your code here
+        try {
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
 
-        OpsgenieClient ogClient = new OpsgenieClient(model.getOpsgenieApiKey(), model.getOpsgenieApiEndpoint());
+            List<MemberModel> members = new ArrayList<>();
 
-        if (model.getMembers() != null) {
-            for (Member member : model.getMembers()) {
-                if (member.getRole() == null) {
-                    member.setRole("user");
+            if (model.getMembers() != null) {
+                for (Member member : model.getMembers()) {
+                    if (member.getRole() == null) {
+                        member.setRole("user");
+                    }
                 }
+                members = model.getMembers()
+                               .stream()
+                               .map(member -> MemberModel.builder()
+                                                         .user(UserModel.builder()
+                                                                        .id(member.getUserId())
+                                                                        .build())
+                                                         .role(member.getRole())
+                                                         .build())
+                               .collect(Collectors.toList());
             }
-        }
-
-
-        List<MemberModel> members = new ArrayList<>();
 
-        if(model.getMembers() != null){
-            members = model.getMembers()
-                    .stream()
-                    .map(member -> MemberModel.builder()
-                            .user(UserModel.builder()
-                                    .id(member.getUserId())
-                                    .build())
-                            .role(member.getRole())
-                            .build())
-                    .collect(Collectors.toList());
-        }
+            CreateTeamRequest createTeamRequest = CreateTeamRequest.builder()
+                                                                   .name(model.getName())
+                                                                   .description(model.getDescription())
+                                                                   .members(members)
+                                                                   .build();
 
-        try {
-            if(model.getTeamId()!=null){
-                throw new OpsgenieClientException("Invalid request",400);
-            }
-            CreateTeamRequest createTeamRequest=CreateTeamRequest.builder()
-                    .name(model.getName())
-                    .description(model.getDescription())
-                    .members(members)
-                    .build();
-            createTeamResponse = ogClient.CreateTeam(createTeamRequest);
+            CreateTeamResponse createTeamResponse = OGClient.CreateTeam(createTeamRequest);
+            model.setTeamId(createTeamResponse.getCreateTeamResponseData()
+                                              .getId());
         } catch (OpsgenieClientException e) {
-            if (e.getCode() == 409) {
-                return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                        .errorCode(HandlerErrorCode.AlreadyExists)
-                        .status(OperationStatus.FAILED)
-                        .build();
-            }
-            if (e.getCode() == 429) {
-                return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                        .errorCode(HandlerErrorCode.Throttling)
-                        .status(OperationStatus.FAILED)
-                        .build();
-            }
-            if (e.getCode() == 400) {
-                return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                        .errorCode(HandlerErrorCode.InvalidRequest)
-                        .message(e.getMessage())
-                        .status(OperationStatus.FAILED)
-                        .build();
-            }
-
-            logger.log(e.getMessage());
-            e.printStackTrace();
-
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(HandlerErrorCode.InternalFailure)
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
         } catch (IOException e) {
-            logger.log("Exception");
-            logger.log(e.getMessage());
-            e.printStackTrace();
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(HandlerErrorCode.InternalFailure)
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetInternalFailureResponse(e.getMessage());
         }
 
-        logger.log("[CREATE] " + createTeamResponse.getCreateTeamResponseData().getId());
-        model.setTeamId(createTeamResponse.getCreateTeamResponseData().getId());
+        logger.log("[CREATE] " + model.getTeamId());
         return ProgressEvent.<ResourceModel, CallbackContext>builder()
                 .resourceModel(model)
                 .status(OperationStatus.SUCCESS)
diff --git a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/DeleteHandler.java b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/DeleteHandler.java
index 226705f..0e1c0e0 100644
--- a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/DeleteHandler.java
+++ b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/DeleteHandler.java
@@ -1,47 +1,33 @@
 package com.atlassian.opsgenie.team;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.team.client.OpsgenieClient;
 import com.atlassian.opsgenie.team.client.OpsgenieClientException;
-import com.atlassian.opsgenie.team.model.DeleteTeamResponse;
+import org.apache.commons.lang3.StringUtils;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
 
-public class DeleteHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.team.Helper.*;
+
+public class DeleteHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-            final AmazonWebServicesClientProxy proxy,
-            final ResourceHandlerRequest<ResourceModel> request,
-            final CallbackContext callbackContext,
-            final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
         final ResourceModel model = request.getDesiredResourceState();
-
-        // TODO : put your code here
-
-        OpsgenieClient ogClient = new OpsgenieClient(model.getOpsgenieApiKey(), model.getOpsgenieApiEndpoint());
-
         try {
-            DeleteTeamResponse deleteTeamResponse = ogClient.DeleteTeam(model.getTeamId());
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
 
-        } catch (OpsgenieClientException e) {
-            if(e.getCode() == 404){
-                logger.log(e.getMessage());
-                e.printStackTrace();
-                return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                        .errorCode(HandlerErrorCode.NotFound)
-                        .status(OperationStatus.FAILED)
-                        .build();
+            if (StringUtils.isEmpty(model.getTeamId())) {
+                return GetServiceFailureResponse(404, "TeamId must be provided.");
             }
-        } catch (IOException e ){
-            logger.log("Exception");
-            logger.log(e.getMessage());
-            e.printStackTrace();
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(HandlerErrorCode.InternalFailure)
-                    .status(OperationStatus.FAILED)
-                    .build();
+
+            OGClient.DeleteTeam(model.getTeamId());
+        } catch (OpsgenieClientException e) {
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
+        } catch (IOException e) {
+            return GetInternalFailureResponse(e.getMessage());
         }
 
         logger.log("[DELETE] " + model.getTeamId());
diff --git a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/Helper.java b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/Helper.java
new file mode 100644
index 0000000..60fe4de
--- /dev/null
+++ b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/Helper.java
@@ -0,0 +1,64 @@
+package com.atlassian.opsgenie.team;
+
+import com.atlassian.opsgenie.team.client.OpsgenieClient;
+import com.atlassian.opsgenie.team.client.OpsgenieClientException;
+import org.apache.commons.lang3.StringUtils;
+import software.amazon.cloudformation.proxy.HandlerErrorCode;
+import software.amazon.cloudformation.proxy.OperationStatus;
+import software.amazon.cloudformation.proxy.ProgressEvent;
+
+/**
+ * @author Furkan Yildiz
+ * @created 7.04.2022
+ */
+public class Helper {
+
+    public static OpsgenieClient CreateOGClient(TypeConfigurationModel typeConfiguration) throws OpsgenieClientException {
+        String opsgenieApiEndpoint = null;
+        String opsgenieApiKey = null;
+
+        if (typeConfiguration != null && typeConfiguration.getOpsgenieCredentials() != null) {
+            opsgenieApiEndpoint = typeConfiguration.getOpsgenieCredentials()
+                                                   .getOpsgenieApiEndpoint();
+            opsgenieApiKey = typeConfiguration.getOpsgenieCredentials()
+                                              .getOpsgenieApiKey();
+        }
+
+        if (StringUtils.isEmpty(opsgenieApiEndpoint) || StringUtils.isEmpty(opsgenieApiKey)) {
+            throw new OpsgenieClientException("OpsgenieApiEndpoint and OpsgenieApiKey must be provided in TypeConfiguration.", 401);
+        }
+
+        return new OpsgenieClient(opsgenieApiEndpoint, opsgenieApiKey);
+    }
+
+    public static ProgressEvent<ResourceModel, CallbackContext> GetInternalFailureResponse(String message) {
+        return ProgressEvent.<ResourceModel, CallbackContext>builder()
+                            .errorCode(HandlerErrorCode.InternalFailure)
+                            .message(message)
+                            .status(OperationStatus.FAILED)
+                            .build();
+    }
+
+    public static ProgressEvent<ResourceModel, CallbackContext> GetServiceFailureResponse(int responseCode, String message) {
+        HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
+        if (responseCode == 400) {
+            errorCode = HandlerErrorCode.InvalidRequest;
+        } else if (responseCode == 401) {
+            errorCode = HandlerErrorCode.InvalidCredentials;
+        } else if (responseCode == 403) {
+            errorCode = HandlerErrorCode.AccessDenied;
+        } else if (responseCode == 404) {
+            errorCode = HandlerErrorCode.NotFound;
+        } else if (responseCode == 409) {
+            errorCode = HandlerErrorCode.AlreadyExists;
+        } else if (responseCode == 429) {
+            errorCode = HandlerErrorCode.Throttling;
+        }
+        return ProgressEvent.<ResourceModel, CallbackContext>builder()
+                            .errorCode(errorCode)
+                            .message(message)
+                            .status(OperationStatus.FAILED)
+                            .build();
+    }
+
+}
diff --git a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/ListHandler.java b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/ListHandler.java
index 38d8551..dfb6410 100644
--- a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/ListHandler.java
+++ b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/ListHandler.java
@@ -1,51 +1,42 @@
 package com.atlassian.opsgenie.team;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.team.client.OpsgenieClient;
 import com.atlassian.opsgenie.team.client.OpsgenieClientException;
-import com.atlassian.opsgenie.team.model.*;
+import com.atlassian.opsgenie.team.model.ListTeamResponse;
+import com.atlassian.opsgenie.team.model.TeamDataModel;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.stream.Collectors;
 
-public class ListHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.team.Helper.*;
+
+public class ListHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-        final AmazonWebServicesClientProxy proxy,
-        final ResourceHandlerRequest<ResourceModel> request,
-        final CallbackContext callbackContext,
-        final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
         final List<ResourceModel> models = new ArrayList<>();
-
-        OpsgenieClient ogClient = new OpsgenieClient(request.getDesiredResourceState().getOpsgenieApiKey(), request.getDesiredResourceState().getOpsgenieApiEndpoint());
-
+        final ResourceModel model = request.getDesiredResourceState();
         try {
-            ListTeamResponse listTeamResponse = ogClient.ListTeam();
-            for(TeamDataModel teamDataModel: listTeamResponse.getTeamDataModel()){
-                ResourceModel.ResourceModelBuilder resourceModelBuilder = ResourceModel.builder();
-                resourceModelBuilder.teamId(teamDataModel.getId());
-                resourceModelBuilder.name(teamDataModel.getName());
-                resourceModelBuilder.description(teamDataModel.getDescription());
-
-
-                resourceModelBuilder.opsgenieApiKey(request.getDesiredResourceState().getOpsgenieApiKey());
-                resourceModelBuilder.opsgenieApiEndpoint(request.getDesiredResourceState().getOpsgenieApiEndpoint());
-
-                models.add(resourceModelBuilder.build());
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
+
+            ListTeamResponse listTeamResponse = OGClient.ListTeam();
+            for (TeamDataModel teamDataModel : listTeamResponse.getTeamDataModel()) {
+                models.add(ResourceModel.builder()
+                                        .teamId(teamDataModel.getId())
+                                        .name(teamDataModel.getName())
+                                        .description(teamDataModel.getDescription())
+                                        .build());
             }
-        } catch (IOException | OpsgenieClientException e) {
-            logger.log("Exception");
-            logger.log(e.getMessage());
-            e.printStackTrace();
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(HandlerErrorCode.InternalFailure)
-                    .status(OperationStatus.FAILED)
-                    .build();
+        } catch (OpsgenieClientException e) {
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
+        } catch (IOException e) {
+            return GetInternalFailureResponse(e.getMessage());
         }
+
         return ProgressEvent.<ResourceModel, CallbackContext>builder()
             .resourceModels(models)
             .status(OperationStatus.SUCCESS)
diff --git a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/ReadHandler.java b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/ReadHandler.java
index 75ead67..1d59ced 100644
--- a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/ReadHandler.java
+++ b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/ReadHandler.java
@@ -1,67 +1,61 @@
 package com.atlassian.opsgenie.team;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.team.client.OpsgenieClient;
 import com.atlassian.opsgenie.team.client.OpsgenieClientException;
-import com.atlassian.opsgenie.team.model.*;
+import com.atlassian.opsgenie.team.model.ReadTeamResponse;
+import org.apache.commons.lang3.StringUtils;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
-import java.util.List;
 import java.util.Arrays;
+import java.util.List;
 import java.util.stream.Collectors;
 
-public class ReadHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.team.Helper.*;
+
+public class ReadHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-        final AmazonWebServicesClientProxy proxy,
-        final ResourceHandlerRequest<ResourceModel> request,
-        final CallbackContext callbackContext,
-        final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
         final ResourceModel model = request.getDesiredResourceState();
+        try {
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
 
-        // TODO : put your code here
+            if (StringUtils.isEmpty(model.getTeamId())) {
+                return GetServiceFailureResponse(404, "TeamId must be provided.");
+            }
 
-        OpsgenieClient ogClient = new OpsgenieClient(model.getOpsgenieApiKey(), model.getOpsgenieApiEndpoint());
+            ReadTeamResponse readTeamResponse = OGClient.ReadTeam(model.getTeamId());
 
-        try {
-            ReadTeamResponse readTeamResponse = ogClient.ReadTeam(model.getTeamId());
+            model.setName(readTeamResponse.getTeamDataModel()
+                                          .getName());
+            model.setDescription(readTeamResponse.getTeamDataModel()
+                                                 .getDescription());
 
-            model.setName(readTeamResponse.getTeamDataModel().getName());
-            model.setDescription(readTeamResponse.getTeamDataModel().getDescription());
+            if (readTeamResponse.getTeamDataModel()
+                                .getMembers() != null) {
 
-            if(readTeamResponse.getTeamDataModel().getMembers()!=null) {
-
-                List<Member> members = readTeamResponse.getTeamDataModel().getMembers().stream()
-                        .map(memberModel -> Member.builder()
-                                .userId(memberModel.getUser().getId())
-                                .role(memberModel.getRole())
-                                .build())
-                        .collect(Collectors.toList());
+                List<Member> members = readTeamResponse.getTeamDataModel()
+                                                       .getMembers()
+                                                       .stream()
+                                                       .map(memberModel -> Member.builder()
+                                                                                 .userId(memberModel.getUser()
+                                                                                                    .getId())
+                                                                                 .role(memberModel.getRole())
+                                                                                 .build())
+                                                       .collect(Collectors.toList());
                 model.setMembers(members);
-            }else {
+            } else {
                 model.setMembers(Arrays.asList());
             }
 
 
         } catch (OpsgenieClientException e) {
-            if(e.getCode() == 404){
-                logger.log(e.getMessage());
-                e.printStackTrace();
-                return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                        .errorCode(HandlerErrorCode.NotFound)
-                        .status(OperationStatus.FAILED)
-                        .build();
-            }
-        } catch (IOException e ){
-            logger.log("Exception");
-            logger.log(e.getMessage());
-            e.printStackTrace();
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(HandlerErrorCode.InternalFailure)
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
+        } catch (IOException e) {
+            return GetInternalFailureResponse(e.getMessage());
         }
 
         logger.log("[READ] " + model.getTeamId());
diff --git a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/UpdateHandler.java b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/UpdateHandler.java
index 2e7d64d..1fab5f1 100644
--- a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/UpdateHandler.java
+++ b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/UpdateHandler.java
@@ -1,88 +1,81 @@
 package com.atlassian.opsgenie.team;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.team.client.OpsgenieClient;
 import com.atlassian.opsgenie.team.client.OpsgenieClientException;
-import com.atlassian.opsgenie.team.model.*;
+import com.atlassian.opsgenie.team.model.MemberModel;
+import com.atlassian.opsgenie.team.model.ReadTeamResponse;
+import com.atlassian.opsgenie.team.model.UpdateTeamRequest;
+import com.atlassian.opsgenie.team.model.UserModel;
+import org.apache.commons.lang3.StringUtils;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
 import java.util.List;
 import java.util.stream.Collectors;
 
-public class UpdateHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.team.Helper.*;
+
+public class UpdateHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-            final AmazonWebServicesClientProxy proxy,
-            final ResourceHandlerRequest<ResourceModel> request,
-            final CallbackContext callbackContext,
-            final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
-        final ResourceModel previousModel = request.getPreviousResourceState();
         final ResourceModel model = request.getDesiredResourceState();
-
-
-        // TODO : put your code here
-
-        OpsgenieClient ogClient = new OpsgenieClient(model.getOpsgenieApiKey(), model.getOpsgenieApiEndpoint());
-
-        List<MemberModel> members = model.getMembers()
-                .stream()
-                .map(member -> MemberModel.builder()
-                        .user(UserModel.builder()
-                                .id(member.getUserId())
-                                .build())
-                        .role(member.getRole())
-                        .build())
-                .collect(Collectors.toList());
-
         try {
-            UpdateTeamResponse updateTeamResponse = ogClient.UpdateTeam(model.getTeamId(), UpdateTeamRequest.builder()
-                    .name(model.getName())
-                    .description(model.getDescription())
-                    .members(members)
-                    .build());
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
 
+            List<MemberModel> members = model.getMembers()
+                                             .stream()
+                                             .map(member -> MemberModel.builder()
+                                                                       .user(UserModel.builder()
+                                                                                      .id(member.getUserId())
+                                                                                      .build())
+                                                                       .role(member.getRole())
+                                                                       .build())
+                                             .collect(Collectors.toList());
 
-            ReadTeamResponse readTeamResponse = ogClient.ReadTeam(model.getTeamId());
 
-            model.setTeamId(readTeamResponse.getTeamDataModel().getId());
-            model.setName(readTeamResponse.getTeamDataModel().getName());
-            model.setDescription(readTeamResponse.getTeamDataModel().getDescription());
+            if (StringUtils.isEmpty(model.getTeamId())) {
+                return GetServiceFailureResponse(404, "TeamId must be provided.");
+            }
 
-            if(readTeamResponse.getTeamDataModel().getMembers() != null){
-                List<Member> membersTemp = readTeamResponse.getTeamDataModel().getMembers().stream()
-                        .map(memberModel -> Member.builder()
-                                .userId(memberModel.getUser().getId())
-                                .role(memberModel.getRole())
-                                .build())
-                        .collect(Collectors.toList());
+            OGClient.UpdateTeam(model.getTeamId(), UpdateTeamRequest.builder()
+                                                                    .name(model.getName())
+                                                                    .description(model.getDescription())
+                                                                    .members(members)
+                                                                    .build());
+
+            ReadTeamResponse readTeamResponse = OGClient.ReadTeam(model.getTeamId());
+
+            model.setTeamId(readTeamResponse.getTeamDataModel()
+                                            .getId());
+            model.setName(readTeamResponse.getTeamDataModel()
+                                          .getName());
+            model.setDescription(readTeamResponse.getTeamDataModel()
+                                                 .getDescription());
+
+            if (readTeamResponse.getTeamDataModel()
+                                .getMembers() != null) {
+                List<Member> membersTemp = readTeamResponse.getTeamDataModel()
+                                                           .getMembers()
+                                                           .stream()
+                                                           .map(memberModel -> Member.builder()
+                                                                                     .userId(memberModel.getUser()
+                                                                                                        .getId())
+                                                                                     .role(memberModel.getRole())
+                                                                                     .build())
+                                                           .collect(Collectors.toList());
 
                 model.setMembers(membersTemp);
             }
 
         } catch (OpsgenieClientException e) {
-            if(e.getCode() == 404){
-                logger.log(e.getMessage());
-                e.printStackTrace();
-                return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                        .errorCode(HandlerErrorCode.NotFound)
-                        .status(OperationStatus.FAILED)
-                        .message(e.getMessage())
-                        .build();
-            }
-        } catch (IOException e ){
-            logger.log("Exception");
-            logger.log(e.getMessage());
-            e.printStackTrace();
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(HandlerErrorCode.InternalFailure)
-                    .status(OperationStatus.FAILED)
-                    .message(e.getMessage())
-                    .build();
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
+        } catch (IOException e) {
+            return GetInternalFailureResponse(e.getMessage());
         }
 
-
         logger.log("[UPDATE] " + model.getTeamId());
         return ProgressEvent.<ResourceModel, CallbackContext>builder()
                 .resourceModel(model)
diff --git a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/client/OpsgenieClient.java b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/client/OpsgenieClient.java
index ec02c63..ef187d8 100644
--- a/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/client/OpsgenieClient.java
+++ b/opsgenie_team/src/main/java/com/atlassian/opsgenie/team/client/OpsgenieClient.java
@@ -13,9 +13,9 @@ public class OpsgenieClient {
 
     private OkHttpClient httpClient;
 
-    public OpsgenieClient(String apiKey, String endpoint) {
-        this.apiKey = apiKey;
+    public OpsgenieClient(String endpoint, String apiKey) {
         this.endpoint = endpoint;
+        this.apiKey = apiKey;
         this.httpClient = new OkHttpClient();
     }
 
diff --git a/opsgenie_user/atlassian-opsgenie-user.json b/opsgenie_user/atlassian-opsgenie-user.json
index 43048d2..6ff94cc 100644
--- a/opsgenie_user/atlassian-opsgenie-user.json
+++ b/opsgenie_user/atlassian-opsgenie-user.json
@@ -2,31 +2,59 @@
   "typeName": "Atlassian::Opsgenie::User",
   "description": "Opsgenie User",
   "sourceUrl": "https://github.com/opsgenie/opsgenie-cloudformation-resources",
+  "typeConfiguration": {
+    "properties": {
+      "OpsgenieCredentials": {
+        "$ref": "#/definitions/OpsgenieCredentials"
+      },
+      "ContractTestSettings": {
+        "$ref": "#/definitions/ContractTestSettings"
+      }
+    },
+    "additionalProperties": false
+  },
   "definitions": {
+    "OpsgenieCredentials": {
+      "description": "Credentials for the Opsgenie API",
+      "properties": {
+        "OpsgenieApiEndpoint": {
+          "type": "string",
+          "pattern": "^https:\/\/api(\\.eu|\\.sandbox|)\\.opsgenie\\.com$"
+        },
+        "OpsgenieApiKey": {
+          "type": "string",
+          "pattern": "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"
+        }
+      },
+      "type": "object",
+      "additionalProperties": false
+    },
+    "ContractTestSettings": {
+      "description": "Contract test settings",
+      "properties": {
+        "DelayEnabled": {
+          "type": "boolean"
+        },
+        "DelaySeconds": {
+          "type": "integer"
+        }
+      },
+      "type": "object",
+      "additionalProperties": false
+    }
   },
   "properties": {
     "UserId": {
       "type": "string"
     },
-    "OpsgenieApiEndpoint": {
-      "type": "string",
-      "pattern": "^https:\/\/api(\\.eu|\\.sandbox|)\\.opsgenie\\.com$",
-      "minLength": 1
-    },
-    "OpsgenieApiKey": {
-      "type": "string",
-      "pattern": "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"
-    },
     "Username": {
       "type": "string",
       "pattern": "^[a-z0-9._+-]+@[a-z0-9]+\\.[a-z]{2,6}$",
-      "description": "Opsgenie Username the mail address of the user",
-      "minLength": 1
+      "description": "Opsgenie Username the mail address of the user"
     },
     "FullName": {
       "type": "string",
       "pattern": "^[a-zA-Z0-9- _.]+$",
-      "minLength": 1,
       "description": "User full name"
     },
     "Role": {
@@ -36,11 +64,9 @@
     }
   },
   "required": [
-    "OpsgenieApiEndpoint",
     "Username",
     "FullName",
-    "Role",
-    "OpsgenieApiKey"
+    "Role"
   ],
   "readOnlyProperties": [
     "/properties/UserId"
@@ -49,6 +75,11 @@
     "/properties/Username",
     "/properties/FullName"
   ],
+  "additionalIdentifiers": [
+    [
+      "/properties/Username"
+    ]
+  ],
   "primaryIdentifier": [
     "/properties/UserId"
   ],
diff --git a/opsgenie_user/overrides.json b/opsgenie_user/overrides.json
index 45cbd17..4ad9be7 100644
--- a/opsgenie_user/overrides.json
+++ b/opsgenie_user/overrides.json
@@ -1,16 +1,12 @@
 {
     "CREATE": {
-        "/OpsgenieApiEndpoint": "",
         "/FullName": "test user123",
         "/Username": "test@test.com",
-        "/OpsgenieApiKey": "",
         "/Role": "User"
     },
     "UPDATE": {
-        "/OpsgenieApiEndpoint": "",
         "/FullName": "test user123",
         "/Username": "test@test.com",
-        "/OpsgenieApiKey": "",
         "/Role": "User"
     }
 
diff --git a/opsgenie_user/pom.xml b/opsgenie_user/pom.xml
index d4cd370..0e5cd47 100644
--- a/opsgenie_user/pom.xml
+++ b/opsgenie_user/pom.xml
@@ -8,13 +8,13 @@
     <parent>
         <groupId>com.atlassian.opsgenie</groupId>
         <artifactId>opsgenie-cloudformation-resources</artifactId>
-        <version>1.0.1</version>
+        <version>2.0.0</version>
     </parent>
 
     <groupId>com.atlassian.opsgenie.user</groupId>
     <artifactId>atlassian-opsgenie-user-handler</artifactId>
     <name>atlassian-opsgenie-user-handler</name>
-    <version>1.0.1</version>
+    <version>2.0.0</version>
     <packaging>jar</packaging>
 
     <properties>
@@ -28,7 +28,7 @@
         <dependency>
             <groupId>software.amazon.cloudformation</groupId>
             <artifactId>aws-cloudformation-rpdk-java-plugin</artifactId>
-            <version>2.0.3</version>
+            <version>2.0.12</version>
         </dependency>
     </dependencies>
 
diff --git a/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/CreateHandler.java b/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/CreateHandler.java
index 0ae1c6a..2a93dba 100644
--- a/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/CreateHandler.java
+++ b/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/CreateHandler.java
@@ -1,74 +1,46 @@
 package com.atlassian.opsgenie.user;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.user.client.OpsgenieClient;
 import com.atlassian.opsgenie.user.client.OpsgenieClientException;
 import com.atlassian.opsgenie.user.model.AddUserRequest;
 import com.atlassian.opsgenie.user.model.AddUserResponse;
 import com.atlassian.opsgenie.user.model.UserRole;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
 
-public class CreateHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.user.Helper.*;
 
+public class CreateHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-            final AmazonWebServicesClientProxy proxy,
-            final ResourceHandlerRequest<ResourceModel> request,
-            final CallbackContext callbackContext,
-            final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
         final ResourceModel model = request.getDesiredResourceState();
-        OpsgenieClient OGClient = new OpsgenieClient(model.getOpsgenieApiEndpoint(), model.getOpsgenieApiKey());
-
-        UserRole tmp = new UserRole();
-        tmp.setName(model.getRole());
-
-        AddUserRequest usr = new AddUserRequest();
-        usr.setFullname(model.getFullName());
-        usr.setRole(tmp);
-        usr.setUsername(model.getUsername());
-        //todo add other fields in future
         try {
-            if(model.getUserId()!=null && !model.equals("")){
-                throw new OpsgenieClientException("Invalid request",400);
-            }
-            logger.log("Sending request for creating user: " + usr.toString());
-            AddUserResponse resp = OGClient.AddUser(usr);
-            model.setUserId(resp.getDataModel().getId());
-            logger.log("ResourceModel: " + model.toString());
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
+            UserRole userRole = new UserRole();
+            userRole.setName(model.getRole());
+
+            AddUserRequest addUserRequest = new AddUserRequest();
+            addUserRequest.setFullname(model.getFullName());
+            addUserRequest.setRole(userRole);
+            addUserRequest.setUsername(model.getUsername());
+
+            AddUserResponse addUserResponse = OGClient.AddUser(addUserRequest);
+            model.setUserId(addUserResponse.getDataModel()
+                                           .getId());
         } catch (OpsgenieClientException e) {
-            logger.log(e.getMessage());
-            HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
-            if (e.getCode() == 409) {
-                errorCode = HandlerErrorCode.AlreadyExists;
-            }
-            if (e.getCode() == 429) {
-                errorCode = HandlerErrorCode.Throttling;
-            }
-            if (e.getCode() == 400) {
-                errorCode = HandlerErrorCode.InvalidRequest;
-            }
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(errorCode)
-                    .resourceModel(model)
-                    .message(e.getMessage())
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
         } catch (IOException e) {
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(HandlerErrorCode.InternalFailure)
-                    .resourceModel(model)
-                    .message(e.getMessage())
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetInternalFailureResponse(e.getMessage());
         }
 
         logger.log("[CREATE] " + model.getUserId());
         return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                .resourceModel(model)
-                .status(OperationStatus.SUCCESS)
-                .build();
+                            .resourceModel(model)
+                            .status(OperationStatus.SUCCESS)
+                            .build();
     }
 }
diff --git a/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/DeleteHandler.java b/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/DeleteHandler.java
index b1e2a35..301fddd 100644
--- a/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/DeleteHandler.java
+++ b/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/DeleteHandler.java
@@ -1,45 +1,39 @@
 package com.atlassian.opsgenie.user;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.user.client.OpsgenieClient;
 import com.atlassian.opsgenie.user.client.OpsgenieClientException;
+import org.apache.commons.lang3.StringUtils;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
 
-public class DeleteHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.user.Helper.*;
+
+public class DeleteHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-            final AmazonWebServicesClientProxy proxy,
-            final ResourceHandlerRequest<ResourceModel> request,
-            final CallbackContext callbackContext,
-            final Logger logger) {
-        ResourceModel model = request.getDesiredResourceState();
-        OpsgenieClient OGClient = new OpsgenieClient(model.getOpsgenieApiEndpoint(), model.getOpsgenieApiKey());
-        logger.log(model.toString());
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
+
+        final ResourceModel model = request.getDesiredResourceState();
         try {
-            if (model.getUserId() != null && !model.getUserId().equals("")) {
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
+            Delay(typeConfiguration);
+            if (StringUtils.isNotEmpty(model.getUserId())) {
                 OGClient.DeleteUser(model.getUserId());
-            } else {
+            } else if (StringUtils.isNotEmpty(model.getUsername())) {
                 OGClient.DeleteUser(model.getUsername());
+            } else {
+                return GetServiceFailureResponse(404, "UserId or UserName must be provided.");
             }
+
         } catch (OpsgenieClientException e) {
-            logger.log(e.getMessage());
-            HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
-            if (e.getCode() == 404) {
-                errorCode = HandlerErrorCode.NotFound;
-            }
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(errorCode)
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
         } catch (IOException e) {
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(HandlerErrorCode.InternalFailure)
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetInternalFailureResponse(e.getMessage());
+        } catch (InterruptedException e) {
+            return GetInternalFailureResponse(e.getMessage());
         }
-
         logger.log("[DELETE] " + model.getUserId());
         return ProgressEvent.<ResourceModel, CallbackContext>builder()
                 .status(OperationStatus.SUCCESS)
diff --git a/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/Helper.java b/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/Helper.java
new file mode 100644
index 0000000..fc6fa6e
--- /dev/null
+++ b/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/Helper.java
@@ -0,0 +1,78 @@
+package com.atlassian.opsgenie.user;
+
+import com.atlassian.opsgenie.user.client.OpsgenieClient;
+import com.atlassian.opsgenie.user.client.OpsgenieClientException;
+import org.apache.commons.lang3.StringUtils;
+import software.amazon.cloudformation.proxy.HandlerErrorCode;
+import software.amazon.cloudformation.proxy.OperationStatus;
+import software.amazon.cloudformation.proxy.ProgressEvent;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Furkan Yildiz
+ * @created 7.04.2022
+ */
+public class Helper {
+    public static void Delay(TypeConfigurationModel typeConfiguration) throws InterruptedException {
+        if (typeConfiguration != null) {
+            ContractTestSettings contractTestSettings = typeConfiguration.getContractTestSettings();
+            if (contractTestSettings != null) {
+                Boolean delayEnabled = contractTestSettings.getDelayEnabled();
+                if (delayEnabled != null && delayEnabled.equals(Boolean.TRUE)) {
+                    Integer delaySeconds = contractTestSettings.getDelaySeconds();
+                    if (delaySeconds != null) TimeUnit.SECONDS.sleep(delaySeconds);
+                }
+            }
+        }
+    }
+
+    public static OpsgenieClient CreateOGClient(TypeConfigurationModel typeConfiguration) throws OpsgenieClientException {
+        String opsgenieApiEndpoint = null;
+        String opsgenieApiKey = null;
+
+        if (typeConfiguration != null && typeConfiguration.getOpsgenieCredentials() != null) {
+            opsgenieApiEndpoint = typeConfiguration.getOpsgenieCredentials()
+                                                   .getOpsgenieApiEndpoint();
+            opsgenieApiKey = typeConfiguration.getOpsgenieCredentials()
+                                              .getOpsgenieApiKey();
+        }
+
+        if (StringUtils.isEmpty(opsgenieApiEndpoint) || StringUtils.isEmpty(opsgenieApiKey)) {
+            throw new OpsgenieClientException("OpsgenieApiEndpoint and OpsgenieApiKey must be provided in TypeConfiguration.", 401);
+        }
+
+        return new OpsgenieClient(opsgenieApiEndpoint, opsgenieApiKey);
+    }
+
+    public static ProgressEvent<ResourceModel, CallbackContext> GetInternalFailureResponse(String message) {
+        return ProgressEvent.<ResourceModel, CallbackContext>builder()
+                            .errorCode(HandlerErrorCode.InternalFailure)
+                            .message(message)
+                            .status(OperationStatus.FAILED)
+                            .build();
+    }
+
+    public static ProgressEvent<ResourceModel, CallbackContext> GetServiceFailureResponse(int responseCode, String message) {
+        HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
+        if (responseCode == 400) {
+            errorCode = HandlerErrorCode.InvalidRequest;
+        } else if (responseCode == 401) {
+            errorCode = HandlerErrorCode.InvalidCredentials;
+        } else if (responseCode == 403) {
+            errorCode = HandlerErrorCode.AccessDenied;
+        } else if (responseCode == 404) {
+            errorCode = HandlerErrorCode.NotFound;
+        } else if (responseCode == 409) {
+            errorCode = HandlerErrorCode.AlreadyExists;
+        } else if (responseCode == 429) {
+            errorCode = HandlerErrorCode.Throttling;
+        }
+        return ProgressEvent.<ResourceModel, CallbackContext>builder()
+                            .errorCode(errorCode)
+                            .message(message)
+                            .status(OperationStatus.FAILED)
+                            .build();
+    }
+
+}
diff --git a/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/ListHandler.java b/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/ListHandler.java
index 66eeff1..f05ac46 100644
--- a/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/ListHandler.java
+++ b/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/ListHandler.java
@@ -1,65 +1,44 @@
 package com.atlassian.opsgenie.user;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.user.client.OpsgenieClient;
 import com.atlassian.opsgenie.user.client.OpsgenieClientException;
 import com.atlassian.opsgenie.user.model.DataModel;
 import com.atlassian.opsgenie.user.model.ListUserResponse;
+import software.amazon.cloudformation.proxy.*;
 
-//import javax.annotation.Resource;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
-public class ListHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.user.Helper.*;
+
+public class ListHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-            final AmazonWebServicesClientProxy proxy,
-            final ResourceHandlerRequest<ResourceModel> request,
-            final CallbackContext callbackContext,
-            final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
         final List<ResourceModel> models = new ArrayList<>();
-        OpsgenieClient OGClient = new OpsgenieClient(request.getDesiredResourceState().getOpsgenieApiEndpoint(), request.getDesiredResourceState().getOpsgenieApiKey());
+        final ResourceModel model = request.getDesiredResourceState();
         try {
-
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
+            Delay(typeConfiguration);
             ListUserResponse listUserResponse = OGClient.ListUsers();
             for (DataModel dataModel : listUserResponse.getDataModel()) {
-                if (!dataModel.getId().equals(request.getDesiredResourceState().getUserId())) {
-                    continue;
-                }
-                ResourceModel tmp = new ResourceModel();
-                tmp.setRole(dataModel.getRole().getName());
-                tmp.setOpsgenieApiEndpoint(request.getDesiredResourceState().getOpsgenieApiEndpoint());
-                tmp.setOpsgenieApiKey(request.getDesiredResourceState().getOpsgenieApiKey());
-                tmp.setUsername(dataModel.getUsername());
-                tmp.setFullName(dataModel.getFullName());
-                tmp.setUserId(dataModel.getId());
-                models.add(tmp);
+                ResourceModel resourceModel = new ResourceModel();
+                resourceModel.setRole(dataModel.getRole()
+                                               .getName());
+                resourceModel.setUsername(dataModel.getUsername());
+                resourceModel.setFullName(dataModel.getFullName());
+                resourceModel.setUserId(dataModel.getId());
+                models.add(resourceModel);
             }
         } catch (OpsgenieClientException e) {
-            HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
-            if (e.getCode() == 404) {
-                errorCode = HandlerErrorCode.NotFound;
-            }
-            if (e.getCode() == 429) {
-                errorCode = HandlerErrorCode.Throttling;
-            }
-            logger.log(e.getMessage());
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(errorCode)
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
         } catch (IOException e) {
-            e.printStackTrace();
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .status(OperationStatus.FAILED)
-                    .build();
-        }
-
-        for(ResourceModel model: models) {
-            logger.log("[CREATE] " + model.getUserId());
+            return GetInternalFailureResponse(e.getMessage());
+        } catch (InterruptedException e) {
+            return GetInternalFailureResponse(e.getMessage());
         }
 
         return ProgressEvent.<ResourceModel, CallbackContext>builder()
diff --git a/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/ReadHandler.java b/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/ReadHandler.java
index c4641f4..3f42430 100644
--- a/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/ReadHandler.java
+++ b/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/ReadHandler.java
@@ -1,59 +1,49 @@
 package com.atlassian.opsgenie.user;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.user.client.OpsgenieClient;
 import com.atlassian.opsgenie.user.client.OpsgenieClientException;
-import com.atlassian.opsgenie.user.model.*;
+import com.atlassian.opsgenie.user.model.GetUserResponse;
+import org.apache.commons.lang3.StringUtils;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
-import java.util.List;
 
-public class ReadHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.user.Helper.*;
+
+public class ReadHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-            final AmazonWebServicesClientProxy proxy,
-            final ResourceHandlerRequest<ResourceModel> request,
-            final CallbackContext callbackContext,
-            final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
         final ResourceModel model = request.getDesiredResourceState();
-        OpsgenieClient OGClient = new OpsgenieClient(model.getOpsgenieApiEndpoint(), model.getOpsgenieApiKey());
         try {
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
             String id;
-            if (model.getUserId() != null && !model.getUserId().equals("")) {
-                logger.log(" userId: " + model.getUserId());
+            if (StringUtils.isNotEmpty(model.getUserId())) {
                 id = model.getUserId();
-            } else {
-                logger.log(" userName: " + model.getUsername());
+            } else if (StringUtils.isNotEmpty(model.getUsername())) {
                 id = model.getUsername();
+            } else {
+                return GetServiceFailureResponse(404, "UserId or UserName must be provided.");
             }
-            GetUserResponse resp = OGClient.GetUser(id);
-            model.setFullName(resp.getDataModel().getFullName());
-            model.setUsername(resp.getDataModel().getUsername());
-            model.setRole(resp.getDataModel().getRole().getName());
+            GetUserResponse getUserResponse = OGClient.GetUser(id);
+            model.setFullName(getUserResponse.getDataModel()
+                                             .getFullName());
+            model.setUsername(getUserResponse.getDataModel()
+                                             .getUsername());
+            model.setRole(getUserResponse.getDataModel()
+                                         .getRole()
+                                         .getName());
+            model.setUserId(getUserResponse.getDataModel()
+                                           .getId());
         } catch (OpsgenieClientException e) {
-            HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
-            if (e.getCode() == 404) {
-                errorCode = HandlerErrorCode.NotFound;
-            }
-            if (e.getCode() == 429) {
-                errorCode = HandlerErrorCode.Throttling;
-            }
-            logger.log(e.getMessage());
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(errorCode)
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
         } catch (IOException e) {
-            e.printStackTrace();
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetInternalFailureResponse(e.getMessage());
         }
 
         logger.log("[READ] " + model.getUserId());
-
         return ProgressEvent.<ResourceModel, CallbackContext>builder()
                 .resourceModel(model)
                 .status(OperationStatus.SUCCESS)
diff --git a/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/UpdateHandler.java b/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/UpdateHandler.java
index 4e44aed..5a6155f 100644
--- a/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/UpdateHandler.java
+++ b/opsgenie_user/src/main/java/com/atlassian/opsgenie/user/UpdateHandler.java
@@ -1,62 +1,46 @@
 package com.atlassian.opsgenie.user;
 
-import software.amazon.cloudformation.proxy.*;
 import com.atlassian.opsgenie.user.client.OpsgenieClient;
 import com.atlassian.opsgenie.user.client.OpsgenieClientException;
-import com.atlassian.opsgenie.user.model.*;
+import com.atlassian.opsgenie.user.model.UpdateUserRequest;
+import com.atlassian.opsgenie.user.model.UserRolerRequest;
+import org.apache.commons.lang3.StringUtils;
+import software.amazon.cloudformation.proxy.*;
 
 import java.io.IOException;
 
-public class UpdateHandler extends BaseHandler<CallbackContext> {
+import static com.atlassian.opsgenie.user.Helper.*;
+
+public class UpdateHandler extends BaseHandler<CallbackContext, TypeConfigurationModel> {
 
     @Override
-    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(
-            final AmazonWebServicesClientProxy proxy,
-            final ResourceHandlerRequest<ResourceModel> request,
-            final CallbackContext callbackContext,
-            final Logger logger) {
+    public ProgressEvent<ResourceModel, CallbackContext> handleRequest(AmazonWebServicesClientProxy proxy, ResourceHandlerRequest<ResourceModel> request, CallbackContext callbackContext,
+                                                                       Logger logger, TypeConfigurationModel typeConfiguration) {
 
         final ResourceModel model = request.getDesiredResourceState();
-        OpsgenieClient OGClient = new OpsgenieClient(model.getOpsgenieApiEndpoint(), model.getOpsgenieApiKey());
-        UserRolerRequest tmp = new UserRolerRequest();
-        UpdateUserRequest usr = new UpdateUserRequest();
-        tmp.setName(model.getRole());
-        usr.setFullname(model.getFullName());
-        usr.setRole(tmp);
-        usr.setUsername(model.getUsername());
         try {
+            OpsgenieClient OGClient = CreateOGClient(typeConfiguration);
+
+            UserRolerRequest userRolerRequest = new UserRolerRequest();
+            UpdateUserRequest updateUserRequest = new UpdateUserRequest();
+            userRolerRequest.setName(model.getRole());
+            updateUserRequest.setFullname(model.getFullName());
+            updateUserRequest.setRole(userRolerRequest);
+            updateUserRequest.setUsername(model.getUsername());
+
             String id;
-            if (model.getUserId() != null && !model.getUserId().equals("")) {
+            if (StringUtils.isNotEmpty(model.getUserId())) {
                 id = model.getUserId();
-            } else {
+            } else if (StringUtils.isNotEmpty(model.getUsername())) {
                 id = model.getUsername();
+            } else {
+                return GetServiceFailureResponse(404, "UserId or UserName must be provided.");
             }
-            UpdateUserResponse resp = OGClient.UpdateUser(id, usr);
-            model.setUserId(request.getDesiredResourceState().getUserId());
-
+            OGClient.UpdateUser(id, updateUserRequest);
         } catch (OpsgenieClientException e) {
-            logger.log(e.getMessage());
-            HandlerErrorCode errorCode = HandlerErrorCode.GeneralServiceException;
-            if (e.getCode() == 409) {
-                errorCode = HandlerErrorCode.AlreadyExists;
-            }
-            if (e.getCode() == 429) {
-                errorCode = HandlerErrorCode.Throttling;
-            }
-            if (e.getCode() == 404) {
-                errorCode = HandlerErrorCode.NotFound;
-            }
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(errorCode)
-                    .message(e.getMessage())
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetServiceFailureResponse(e.getCode(), e.getMessage());
         } catch (IOException e) {
-            logger.log(e.getMessage());
-            return ProgressEvent.<ResourceModel, CallbackContext>builder()
-                    .errorCode(HandlerErrorCode.InternalFailure)
-                    .status(OperationStatus.FAILED)
-                    .build();
+            return GetInternalFailureResponse(e.getMessage());
         }
 
         logger.log("[UPDATE] " + model.getUserId());
diff --git a/pom.xml b/pom.xml
index a95e576..3b47f0e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
 
     <groupId>com.atlassian.opsgenie</groupId>
     <artifactId>opsgenie-cloudformation-resources</artifactId>
-    <version>1.0.1</version>
+    <version>2.0.0</version>
     <packaging>pom</packaging>
 
     <modules>
@@ -22,6 +22,7 @@
         <guava.version>30.1.1-jre</guava.version>
         <httpcomponents.version>4.5.13</httpcomponents.version>
         <common.beanutils.version>1.9.4</common.beanutils.version>
+        <slf4j.version>1.7.36</slf4j.version>
     </properties>
 
     <dependencies>
@@ -29,7 +30,7 @@
         <dependency>
             <groupId>software.amazon.cloudformation</groupId>
             <artifactId>aws-cloudformation-rpdk-java-plugin</artifactId>
-            <version>2.0.3</version>
+            <version>2.0.12</version>
         </dependency>
         <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
         <dependency>
@@ -80,6 +81,16 @@
             <version>3.0.16</version>
         </dependency>
 
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>${slf4j.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>${slf4j.version}</version>
+        </dependency>
 
     </dependencies>
 
diff --git a/register-resource.sh b/register-resource.sh
index 41ac4b8..809d731 100755
--- a/register-resource.sh
+++ b/register-resource.sh
@@ -20,7 +20,7 @@ function readJson() {
 }
 
 
-mvn package
+mvn package -B
 if [[ "$?" -ne 0 ]] ; then
   echo 'build failed'; exit 1
 fi
diff --git a/requirements.txt b/requirements.txt
index f01b1c0..9b190bf 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
-cloudformation-cli==0.2.12
+cloudformation-cli==0.2.24
 cloudformation-cli-go-plugin==2.0.4
-cloudformation-cli-java-plugin==2.0.5
-cloudformation-cli-python-plugin==2.1.3
+cloudformation-cli-java-plugin==2.0.12
+cloudformation-cli-python-plugin==2.1.5
 cloudformation-cli-typescript-plugin==1.0.0
\ No newline at end of file
diff --git a/script.sh b/script.sh
index a4558e8..14eb359 100755
--- a/script.sh
+++ b/script.sh
@@ -4,22 +4,20 @@
 read -r -d '' PYSCRIPT << ENDPY
 import json
 import os
-def updateJsonFile():
+from os.path import expanduser
+def generateTypeConfigurationJson():
+  data = {
+      'OpsgenieCredentials' : {
+          'OpsgenieApiEndpoint' : os.getenv('OPSGENIE_API_ENDPOINT','https://api.opsgenie.com'),
+          'OpsgenieApiKey' :  os.getenv('OPSGENIE_API_KEY',"")
+      }
+  }
+  with open('typeConfiguration.json', 'w+') as f:
+      json.dump(data, f, indent=4)
 
-    with open('overrides.json', 'r') as f:
-        data = json.load(f)
-        data["CREATE"]["/OpsgenieApiKey"]= os.environ['OPSGENIE_API_KEY']
-        data["CREATE"]["/OpsgenieApiEndpoint"]= os.environ['OPSGENIE_API_ENDPOINT']
-        if "UPDATE" in data:
-          data["UPDATE"]["/OpsgenieApiKey"]= os.environ['OPSGENIE_API_KEY']
-          data["UPDATE"]["/OpsgenieApiEndpoint"]= os.environ['OPSGENIE_API_ENDPOINT']
-        print(data);
-        with open('overrides.json', 'w') as f1:
-            json.dump(data, f1, indent=4)
-
-updateJsonFile()
+generateTypeConfigurationJson()
 ENDPY
 
 # execute python and fail on error
 
-echo "$PYSCRIPT" |python - || exit 1
+echo "$PYSCRIPT" |python3 - || exit 1
diff --git a/team_template.yaml b/team_template.yml
similarity index 92%
rename from team_template.yaml
rename to team_template.yml
index 468b932..59170b5 100644
--- a/team_template.yaml
+++ b/team_template.yml
@@ -13,11 +13,13 @@ Resources:
     Properties:
       Handler: com.atlassian.opsgenie.team.HandlerWrapper::handleRequest
       Runtime: java8
-      CodeUri: opsgenie_team/target/atlassian-opsgenie-team-handler-1.0-SNAPSHOT.jar
+      CodeUri: opsgenie_team/target/atlassian-opsgenie-team-handler-2.0.0.jar
+      Timeout: 60
 
   TestEntrypoint:
     Type: AWS::Serverless::Function
     Properties:
       Handler: com.atlassian.opsgenie.team.HandlerWrapper::testEntrypoint
       Runtime: java8
-      CodeUri: opsgenie_team/target/atlassian-opsgenie-team-handler-1.0-SNAPSHOT.jar
\ No newline at end of file
+      CodeUri: opsgenie_team/target/atlassian-opsgenie-team-handler-2.0.0.jar
+      Timeout: 60
\ No newline at end of file
diff --git a/user_script.sh b/user_script.sh
new file mode 100755
index 0000000..f77df01
--- /dev/null
+++ b/user_script.sh
@@ -0,0 +1,27 @@
+#
+#!/bin/bash
+
+read -r -d '' PYSCRIPT << ENDPY
+import json
+import os
+from os.path import expanduser
+def generateTypeConfigurationJson():
+  data = {
+      'OpsgenieCredentials' : {
+          'OpsgenieApiEndpoint' : os.getenv('OPSGENIE_API_ENDPOINT','https://api.opsgenie.com'),
+          'OpsgenieApiKey' :  os.getenv('OPSGENIE_API_KEY',"")
+      },
+      'ContractTestSettings': {
+          'DelayEnabled' : os.getenv('DELAY_ENABLED','true').lower() in ('true', '1', 'yes'),
+          'DelaySeconds' : int(os.getenv('DELAY_SECONDS','10')),
+      }
+  }
+  with open('typeConfiguration.json', 'w+') as f:
+      json.dump(data, f, indent=4)
+
+generateTypeConfigurationJson()
+ENDPY
+
+# execute python and fail on error
+
+echo "$PYSCRIPT" |python3 - || exit 1
diff --git a/user_template.yml b/user_template.yml
index 37bca53..e160eb4 100644
--- a/user_template.yml
+++ b/user_template.yml
@@ -13,11 +13,13 @@ Resources:
     Properties:
       Handler: com.atlassian.opsgenie.user.HandlerWrapper::handleRequest
       Runtime: java8
-      CodeUri: opsgenie_user/target/atlassian-opsgenie-user-handler-1.0-SNAPSHOT.jar
+      CodeUri: opsgenie_user/target/atlassian-opsgenie-user-handler-2.0.0.jar
+      Timeout: 60
 
   TestEntrypoint:
     Type: AWS::Serverless::Function
     Properties:
       Handler: com.atlassian.opsgenie.user.HandlerWrapper::testEntrypoint
       Runtime: java8
-      CodeUri: opsgenie_user/target/atlassian-opsgenie-user-handler-1.0-SNAPSHOT.jar
\ No newline at end of file
+      CodeUri: opsgenie_user/target/atlassian-opsgenie-user-handler-2.0.0.jar
+      Timeout: 60
\ No newline at end of file


Test patch:
diff --git a/examples/e2e/complete.json b/examples/e2e/complete.json
index 4aa41a4..5eede25 100644
--- a/examples/e2e/complete.json
+++ b/examples/e2e/complete.json
@@ -1,33 +1,11 @@
 {
   "AWSTemplateFormatVersion": "2010-09-09",
-  "Description": "Opsgenie Test Users",
-  "Parameters": {
-    "OpsgenieApiKey": {
-      "Description": "Enter Opsgenie Api Key",
-      "Type": "String"
-    },
-    "OpsgenieApiEndpoint": {
-      "Description": "Enter Opsgenie Api endpoint",
-      "Type": "String",
-      "Default": "https://api.opsgenie.com",
-      "AllowedValues": [
-        "https://api.opsgenie.com",
-        "https://api.eu.opsgenie.com",
-        "https://api.sandbox.opsgenie.com"
-      ]
-    }
-  },
+  "Description": "Opsgenie Cloudformation Resources End to End Test",
   "Resources": {
     "UserA": {
       "Type": "Atlassian::Opsgenie::User",
       "Properties": {
-        "OpsgenieApiKey": {
-          "Ref": "OpsgenieApiKey"
-        },
-        "OpsgenieApiEndpoint": {
-          "Ref": "OpsgenieApiEndpoint"
-        },
-        "Username": "user.a@example.com",
+        "Username": "usera@cfntest.com",
         "FullName": "User A",
         "Role": "User"
       }
@@ -35,13 +13,7 @@
     "UserB": {
       "Type": "Atlassian::Opsgenie::User",
       "Properties": {
-        "OpsgenieApiKey": {
-          "Ref": "OpsgenieApiKey"
-        },
-        "OpsgenieApiEndpoint": {
-          "Ref": "OpsgenieApiEndpoint"
-        },
-        "Username": "user.b@example.com",
+        "Username": "userb@cfntest.com",
         "FullName": "User B",
         "Role": "User"
       }
@@ -49,12 +21,6 @@
     "TeamA": {
       "Type": "Atlassian::Opsgenie::Team",
       "Properties": {
-        "OpsgenieApiKey": {
-          "Ref": "OpsgenieApiKey"
-        },
-        "OpsgenieApiEndpoint": {
-          "Ref": "OpsgenieApiEndpoint"
-        },
         "Name": "cloudformation-ops-team-test",
         "Description": "Test team with 2 user for demonstration",
         "Members": [
@@ -80,57 +46,62 @@
     "IntegrationTest": {
       "Type": "Atlassian::Opsgenie::Integration",
       "Properties": {
-        "OpsgenieApiKey": {
-          "Ref": "OpsgenieApiKey"
-        },
-        "OpsgenieApiEndpoint": {
-          "Ref": "OpsgenieApiEndpoint"
-        },
-        "IntegrationType": "AmazonSns",
-        "Name": "test awsSns test",
+        "IntegrationType": "API",
+        "Name": "test integration",
         "Responders": [
           {
             "type": "team",
             "name": "cloudformation-ops-team-test"
           }
         ],
-        "Enabled": true
+        "Enabled": true,
+        "OwnerTeamName" : "cloudformation-ops-team-test",
+        "AllowReadAccess": true,
+        "AllowWriteAccess": true,
+        "AllowDeleteAccess": true,
+        "AllowConfigurationAccess": false
       },
       "DependsOn": [
         "TeamA"
       ]
+    }
+  },
+  "Outputs": {
+    "UserA": {
+      "Description": "Opsgenie UserId",
+      "Value": {
+        "Fn::GetAtt": [
+          "UserA",
+          "UserId"
+        ]
+      }
     },
-    "MySns": {
-      "Type": "AWS::SNS::Topic",
-      "Properties": {
-        "DisplayName": "opsgenie-test-aws",
-        "Subscription": [
-          {
-            "Endpoint": {
-              "Fn::Join": [
-                "",
-                [
-                  {
-                    "Ref": "OpsgenieApiEndpoint"
-                  },
-                  "/v1/json/amazonsns?apiKey=",
-                  {
-                    "Fn::GetAtt": [
-                      "IntegrationTest",
-                      "IntegrationApiKey"
-                    ]
-                  }
-                ]
-              ]
-            },
-            "Protocol": "https"
-          }
-        ],
-        "TopicName": "opsgenie-test-demo-134"
-      },
-      "DependsOn": [
-        "IntegrationTest"
-      ]
+    "UserB": {
+      "Description": "Opsgenie UserId",
+      "Value": {
+        "Fn::GetAtt": [
+          "UserB",
+          "UserId"
+        ]
+      }
+    },
+    "TeamId": {
+      "Description": "Opsgenie TeamId",
+      "Value": {
+        "Fn::GetAtt": [
+          "TeamA",
+          "TeamId"
+        ]
+      }
+    },
+    "IntegrationId": {
+      "Description": "Opsgenie IntegrationId",
+      "Value": {
+        "Fn::GetAtt": [
+          "IntegrationTest",
+          "IntegrationId"
+        ]
+      }
     }
   }
 }
\ No newline at end of file
diff --git a/test-check.sh b/test-check.sh
index c291b9e..1128946 100755
--- a/test-check.sh
+++ b/test-check.sh
@@ -19,6 +19,13 @@ function readJson {
   fi;
 }
 
+aws cloudformation set-type-configuration \
+    --region $REGION \
+    --type RESOURCE \
+    --type-name $RESOURCE_NAME \
+    --configuration-alias default \
+    --configuration file://typeConfiguration.json
+
 aws cloudformation test-type --type RESOURCE --type-name $RESOURCE_NAME --log-delivery-bucket $BUCKET_NAME> test_arn.json
 
 TEST_ARN=`readJson test_arn.json TypeVersionArn` || exit 1;
@@ -43,5 +50,4 @@ else
   echo $TEST_STATUS
   echo $TEST_STATUS > test_result.txt
   exit 1
-fi
-
+fi
\ No newline at end of file