diff --git a/Sources/SLSAdapter/Function+Extensions.swift b/Sources/SLSAdapter/Function+Extensions.swift
index 7551f74..9dacba1 100644
--- a/Sources/SLSAdapter/Function+Extensions.swift
+++ b/Sources/SLSAdapter/Function+Extensions.swift
@@ -91,4 +91,25 @@ public extension Function {
             events: [.init(httpAPI: event)]
         )
     }
+    
+    static func httpApiLambda(
+        handler: String,
+        description: String?,
+        memorySize: Int?,
+        environment: YAMLContent?,
+        runtime: Runtime?,
+        package: Package?,
+        event: EventHTTPAPI
+    ) throws -> Function {
+        Function(
+            handler: handler,
+            runtime: runtime,
+            memorySize: memorySize,
+            environment: environment,
+            description: description ?? "[${sls:stage}] \(event.method) \(event.path)",
+            package: package,
+            layers: nil,
+            events: [.init(httpAPI: event)]
+        )
+    }
 }
diff --git a/Tests/SLSAdapterTests/Fixtures/serverless_webhook.yml b/Tests/SLSAdapterTests/Fixtures/serverless_webhook.yml
new file mode 100644
index 0000000..8a1b24f
--- /dev/null
+++ b/Tests/SLSAdapterTests/Fixtures/serverless_webhook.yml
@@ -0,0 +1,59 @@
+service: swift-webhook
+frameworkVersion: '3'
+configValidationMode: warn
+useDotenv: false
+provider:
+  name: aws
+  region: us-east-1
+  disableRollback: false
+  runtime: provided.al2
+  httpApi:
+    payload: '2.0'
+    cors: false
+  architecture: arm64
+  versionFunctions: true
+  iam:
+    role:
+      statements:
+      - Effect: Allow
+        Action:
+        - logs:CreateLogGroup
+        - logs:CreateLogStream
+        - logs:PutLogEvents
+        Resource: '*'
+
+package:
+  individually: true
+functions:
+  postWebHook:
+    handler: post-webhook
+    memorySize: 256
+    description: '[${sls:stage}] post /webhook'
+    package:
+      artifact: build/WebHook/WebHook.zip
+    events:
+    - httpApi:
+        path: /webhook
+        method: post
+  getWebHook:
+    handler: get-webhook
+    memorySize: 256
+    description: '[${sls:stage}] get /webhook'
+    package:
+      artifact: build/WebHook/WebHook.zip
+    events:
+    - httpApi:
+        path: /webhook
+        method: get
+  githubWebHook:
+    handler: github-webhook
+    memorySize: 256
+    description: '[${sls:stage}] post /github-webhook'
+    package:
+      artifact: build/GitHubWebHook/GitHubWebHook.zip
+    environment:
+      WEBHOOK_SECRET: '${ssm:/dev/swift-webhook/webhook_secret}'
+    events:
+    - httpApi:
+        path: /github-webhook
+        method: post
diff --git a/Tests/SLSAdapterTests/HttpAPILambdaParams.swift b/Tests/SLSAdapterTests/HttpAPILambdaParams.swift
new file mode 100644
index 0000000..ac66258
--- /dev/null
+++ b/Tests/SLSAdapterTests/HttpAPILambdaParams.swift
@@ -0,0 +1,61 @@
+/*
+ Copyright 2023 (c) Andrea Scuderi - https://github.com/swift-sprinter
+ 
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+import Foundation
+import SLSAdapter
+import Yams
+
+public struct HttpAPILambdaParams {
+    public let name: String
+    public let handler: String
+    public let event: EventHTTPAPI
+    public let environment: YAMLContent?
+    public let artifact: String
+    
+    public init(name: String, handler: String, event: EventHTTPAPI, environment: YAMLContent?, artifact: String) {
+        self.name = name
+        self.handler = handler
+        self.event = event
+        self.environment = environment
+        self.artifact = artifact
+    }
+}
+
+public extension Function {
+    static func httpAPILambda(params: HttpAPILambdaParams, memorySize: Int?) throws -> Function {
+        try .httpApiLambda(
+            handler: params.handler,
+            description: nil,
+            memorySize: memorySize,
+            environment: params.environment,
+            runtime: nil,
+            package: .init(patterns: nil,
+                           individually: nil,
+                           artifact: params.artifact),
+            event: params.event
+        )
+    }
+}
+
+extension Array where Element == HttpAPILambdaParams {
+    func buildFunctions(memorySize: Int) throws -> [String: Function] {
+        var functions: [String: Function] = [:]
+        for lambdasParam in self {
+            functions[lambdasParam.name] = try Function.httpAPILambda(params: lambdasParam, memorySize: memorySize)
+        }
+        return functions
+    }
+}
diff --git a/Tests/SLSAdapterTests/SLSAdapterTests.swift b/Tests/SLSAdapterTests/SLSAdapterTests.swift
index 9759745..e05f060 100644
--- a/Tests/SLSAdapterTests/SLSAdapterTests.swift
+++ b/Tests/SLSAdapterTests/SLSAdapterTests.swift
@@ -31,7 +31,7 @@ final class SwiftSlsAdapterTests: XCTestCase {
         return try Data(contentsOf: fixtureUrl)
     }
     
-    func testReadServerlessYml() throws {
+    func test_ReadServerlessYml() throws {
         let serverlessYml = try fixture(name: "serverless", type: "yml")
         
         let decoder = YAMLDecoder()
@@ -162,7 +162,7 @@ final class SwiftSlsAdapterTests: XCTestCase {
         XCTAssertEqual(productTableProperties.dictionary?["BillingMode"]?.string, "PAY_PER_REQUEST")
     }
     
-    func testReadWriteServerlessYml() throws {
+    func test_ReadWriteServerlessYml() throws {
         let serverlessYml = try fixture(name: "serverless", type: "yml")
         let decoder = YAMLDecoder()
         let serverlessConfig = try decoder.decode(ServerlessConfig.self, from: serverlessYml)
@@ -179,7 +179,7 @@ final class SwiftSlsAdapterTests: XCTestCase {
         let path: String
     }
     
-    func testInitServerlessYml() throws {
+    func test_InitServerlessYml() throws {
         let decoder = YAMLDecoder()
         let serverlessYml = try fixture(name: "serverless", type: "yml")
         let serverlessConfig2 = try decoder.decode(ServerlessConfig.self, from: serverlessYml)
@@ -215,7 +215,7 @@ final class SwiftSlsAdapterTests: XCTestCase {
         XCTAssertEqual(serverlessConfig.resources, serverlessConfig2.resources)
     }
     
-    func testInitServerlessNolLayerYml() throws {
+    func test_InitServerlessNolLayerYml() throws {
         let decoder = YAMLDecoder()
         let serverlessYml = try fixture(name: "serverless_no_layer", type: "yml")
         let serverlessConfig2 = try decoder.decode(ServerlessConfig.self, from: serverlessYml)
diff --git a/Tests/SLSAdapterTests/ServerlessConfig+Exensions.swift b/Tests/SLSAdapterTests/ServerlessConfig+Exensions.swift
index acfcd9d..2e5fe31 100644
--- a/Tests/SLSAdapterTests/ServerlessConfig+Exensions.swift
+++ b/Tests/SLSAdapterTests/ServerlessConfig+Exensions.swift
@@ -129,75 +129,110 @@ extension ServerlessConfig {
         executable: String,
         artifact: String
     ) throws -> ServerlessConfig {
-            let keyedPath = "\(httpAPIPath)/{\(dynamoDBKey)}"
-            let dynamoResourceName = "\(executable)Table"
-            
-            let environmentTableName = "DYNAMO_DB_TABLE_NAME"
-            let environmentKeyName = "DYNAMO_DB_KEY"
-
-            let iam = Iam(
-                role: Role(
-                    statements: [.allowLogAccess(resource: try YAMLContent(with: "*")),
-                                 .allowDynamoDBReadWrite(resource: try YAMLContent(with: [["Fn::GetAtt": [dynamoResourceName, "Arn"]]]))]
-                )
+        let keyedPath = "\(httpAPIPath)/{\(dynamoDBKey)}"
+        let dynamoResourceName = "\(executable)Table"
+        
+        let environmentTableName = "DYNAMO_DB_TABLE_NAME"
+        let environmentKeyName = "DYNAMO_DB_KEY"
+        let dynamoResource = try YAMLContent(with: [["Fn::GetAtt": [dynamoResourceName, "Arn"]]])
+        let iam = Iam(
+            role: Role(
+                statements: [.allowLogAccess(resource: try YAMLContent(with: "*")),
+                             .allowDynamoDBReadWrite(resource: dynamoResource)]
             )
-            let environment = try YAMLContent(with: [environmentTableName: "${self:custom.tableName}",
-                                                       environmentKeyName: "${self:custom.keyName}"])
-            let provider = Provider(
-                name: .aws,
-                region: region,
-                runtime: runtime,
-                environment: environment,
-                architecture: architecture,
-                httpAPI: .init(
-                    payload: "2.0",
-                    cors: true,
-                    authorizers:
+        )
+        let environment = try YAMLContent(with: [environmentTableName: "${self:custom.tableName}",
+                                                   environmentKeyName: "${self:custom.keyName}"])
+        let provider = Provider(
+            name: .aws,
+            region: region,
+            runtime: runtime,
+            environment: environment,
+            architecture: architecture,
+            httpAPI: .init(
+                payload: "2.0",
+                cors: true,
+                authorizers:
                         .dictionary([
                             "JWTAuthorizer": .buildJWTAuthorizer(issuerUrl: "https://appleid.apple.com",
-                                                                                audience: ["com.mydomain.myhost"]),
+                                                                 audience: ["com.mydomain.myhost"]),
                             "customAuthorizer": .buildCustomAuthorizer(name: "LambdaAuthorizer",
                                                                        functionName: "lambdaAuthorizer",
                                                                        identitySource: ["$request.header.SEC-X-API-KEY",
                                                                                         "$request.header.User-Agent"])
                         ])
-                ),
-                iam: iam
-            )
-            let custom = try YAMLContent(with: ["tableName": "\(dynamoDBTableNamePrefix)-table-${sls:stage}",
-                                                "keyName": dynamoDBKey])
-            
-            let endpoints = [
-                Endpoint(handler: "create", method: .post, path: httpAPIPath),
-                Endpoint(handler: "read", method: .get, path: keyedPath),
-                Endpoint(handler: "update", method: .put, path: httpAPIPath),
-                Endpoint(handler: "delete", method: .delete, path: keyedPath),
-                Endpoint(handler: "list", method: .get, path: httpAPIPath)
-            ]
-            var functions: [String: Function] = [:]
-            for endpoint in endpoints {
-                let function = try Function.httpApiLambda(
-                    handler: "\(endpoint.handler)",
-                    description: nil,
-                    memorySize: memorySize,
-                    runtime: nil,
-                    package: nil,
-                    event: .init(path: endpoint.path, method: endpoint.method)
-                )
-                functions["\(endpoint.handler)\(executable)"] = function
-            }
-            
-            let resource = Resource.dynamoDBResource(tableName: "${self:custom.tableName}", key: "${self:custom.keyName}")
-            let resources = Resources.resources(with: [dynamoResourceName: resource])
-            
-            return ServerlessConfig(
-                service: service,
-                provider: provider,
-                package: .init(patterns: nil, individually: nil, artifact: artifact),
-                custom: custom,
-                layers: nil,
-                functions: functions,
-                resources: try YAMLContent(with: resources)
+            ),
+            iam: iam
+        )
+        let custom = try YAMLContent(with: ["tableName": "\(dynamoDBTableNamePrefix)-table-${sls:stage}",
+                                            "keyName": dynamoDBKey])
+        
+        let endpoints = [
+            Endpoint(handler: "create", method: .post, path: httpAPIPath),
+            Endpoint(handler: "read", method: .get, path: keyedPath),
+            Endpoint(handler: "update", method: .put, path: httpAPIPath),
+            Endpoint(handler: "delete", method: .delete, path: keyedPath),
+            Endpoint(handler: "list", method: .get, path: httpAPIPath)
+        ]
+        var functions: [String: Function] = [:]
+        for endpoint in endpoints {
+            let function = try Function.httpApiLambda(
+                handler: "\(endpoint.handler)",
+                description: nil,
+                memorySize: memorySize,
+                runtime: nil,
+                package: nil,
+                event: .init(path: endpoint.path, method: endpoint.method)
             )
+            functions["\(endpoint.handler)\(executable)"] = function
         }
+        
+        let resource = Resource.dynamoDBResource(tableName: "${self:custom.tableName}", key: "${self:custom.keyName}")
+        let resources = Resources.resources(with: [dynamoResourceName: resource])
+        
+        return ServerlessConfig(
+            service: service,
+            provider: provider,
+            package: .init(patterns: nil, individually: nil, artifact: artifact),
+            custom: custom,
+            layers: nil,
+            functions: functions,
+            resources: try YAMLContent(with: resources)
+        )
+    }
+    
+    static func webhookLambdaAPI(
+        service: String,
+        region: Region,
+        runtime: Runtime,
+        architecture: Architecture,
+        memorySize: Int,
+        lambdasParams: [HttpAPILambdaParams]
+    ) throws -> ServerlessConfig {
+        let iam = Iam(
+            role: Role(
+                statements: [.allowLogAccess(resource: try YAMLContent(with: "*"))]
+            )
+        )
+        let provider = Provider(
+            name: .aws,
+            region: region,
+            runtime: runtime,
+            environment: nil,
+            architecture: architecture,
+            httpAPI: .init(payload: "2.0", cors: false),
+            iam: iam
+        )
+        let package = Package(patterns: nil, individually: true)
+        let functions = try lambdasParams.buildFunctions(memorySize: memorySize)
+        return ServerlessConfig(
+            service: service,
+            provider: provider,
+            package: package,
+            custom: nil,
+            layers: nil,
+            functions: functions,
+            resources: nil
+        )
+    }
 }
diff --git a/Tests/SLSAdapterTests/ServerlessHttpAPILambdaTests.swift b/Tests/SLSAdapterTests/ServerlessHttpAPILambdaTests.swift
new file mode 100644
index 0000000..e5c091b
--- /dev/null
+++ b/Tests/SLSAdapterTests/ServerlessHttpAPILambdaTests.swift
@@ -0,0 +1,167 @@
+/*
+ Copyright 2023 (c) Andrea Scuderi - https://github.com/swift-sprinter
+ 
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ 
+ http://www.apache.org/licenses/LICENSE-2.0
+ 
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+import Foundation
+import SLSAdapter
+import XCTest
+import Yams
+
+final class ServerlessHttpAPILambdaTests: XCTestCase {
+    
+    enum TestError: Error {
+        case missingFixture
+    }
+    
+    func fixture(name: String, type: String) throws -> Data {
+        guard let fixtureUrl = Bundle.module.url(forResource: name, withExtension: type, subdirectory: "Fixtures") else {
+            throw TestError.missingFixture
+        }
+        return try Data(contentsOf: fixtureUrl)
+    }
+
+    func test_ReadServerlessWebhook() throws {
+        let serverlessYml = try fixture(name: "serverless_webhook", type: "yml")
+        
+        let decoder = YAMLDecoder()
+        let serverlessConfig = try decoder.decode(ServerlessConfig.self, from: serverlessYml)
+        XCTAssertEqual(serverlessConfig.service, "swift-webhook")
+        XCTAssertEqual(serverlessConfig.frameworkVersion, "3")
+        XCTAssertEqual(serverlessConfig.configValidationMode, .warn)
+        XCTAssertEqual(serverlessConfig.useDotenv, false)
+        
+        XCTAssertEqual(serverlessConfig.package?.individually, true)
+        
+        XCTAssertNil(serverlessConfig.custom)
+        
+        let provider = serverlessConfig.provider
+        XCTAssertEqual(provider.name, .aws)
+        XCTAssertEqual(provider.region, .us_east_1)
+        
+        let httpAPI = try XCTUnwrap(provider.httpAPI)
+        XCTAssertEqual(httpAPI.payload, "2.0")
+        XCTAssertEqual(httpAPI.cors, false)
+        
+        XCTAssertEqual(provider.runtime, .providedAl2)
+        XCTAssertEqual(provider.architecture, .arm64)
+        
+        let iam = try XCTUnwrap(provider.iam)
+        
+        var role: Role?
+        if case .role(let value) = iam {
+            role = value
+        }
+        
+        XCTAssertEqual(role?.statements.count, 1)
+        
+        let statement1 = try XCTUnwrap(role?.statements.first)
+        let actionExpectation1 = [
+            "logs:CreateLogGroup",
+            "logs:CreateLogStream",
+            "logs:PutLogEvents"
+        ]
+        XCTAssertEqual(statement1.effect, "Allow")
+        XCTAssertEqual(statement1.action, actionExpectation1)
+        XCTAssertEqual(statement1.resource.value, "*")
+        
+        let postWebHook = try XCTUnwrap(serverlessConfig.functions?["postWebHook"])
+        XCTAssertEqual(postWebHook.handler, "post-webhook")
+        XCTAssertEqual(postWebHook.memorySize, 256)
+        XCTAssertEqual(postWebHook.description, "[${sls:stage}] post /webhook")
+        let artifact = postWebHook.package?.artifact
+        XCTAssertEqual(artifact, "build/WebHook/WebHook.zip")
+        XCTAssertEqual(postWebHook.events.first?.httpAPI?.path, "/webhook")
+        XCTAssertEqual(postWebHook.events.first?.httpAPI?.method, .post)
+        
+        let getWebHook = try XCTUnwrap(serverlessConfig.functions?["getWebHook"])
+        XCTAssertEqual(getWebHook.handler, "get-webhook")
+        XCTAssertEqual(getWebHook.memorySize, 256)
+        XCTAssertEqual(getWebHook.description, "[${sls:stage}] get /webhook")
+        let artifact2 = getWebHook.package?.artifact
+        XCTAssertEqual(artifact2, "build/WebHook/WebHook.zip")
+        XCTAssertEqual(getWebHook.events.first?.httpAPI?.path, "/webhook")
+        XCTAssertEqual(getWebHook.events.first?.httpAPI?.method, .get)
+        
+        let githubWebHook = try XCTUnwrap(serverlessConfig.functions?["githubWebHook"])
+        XCTAssertEqual(githubWebHook.handler, "github-webhook")
+        XCTAssertEqual(githubWebHook.memorySize, 256)
+        XCTAssertEqual(githubWebHook.description, "[${sls:stage}] post /github-webhook")
+        let artifact3 = githubWebHook.package?.artifact
+        XCTAssertEqual(artifact3, "build/GitHubWebHook/GitHubWebHook.zip")
+        let environment = githubWebHook.environment?.dictionary
+        let webBookSecret = try XCTUnwrap(environment?["WEBHOOK_SECRET"]?.string)
+        XCTAssertEqual(webBookSecret, "${ssm:/dev/swift-webhook/webhook_secret}")
+        XCTAssertEqual(githubWebHook.events.first?.httpAPI?.path, "/github-webhook")
+        XCTAssertEqual(githubWebHook.events.first?.httpAPI?.method, .post)
+    }
+    
+    func test_WriteServerlessWebook() throws {
+        let serverlessYml = try fixture(name: "serverless_webhook", type: "yml")
+        let decoder = YAMLDecoder()
+        let serverlessConfig = try decoder.decode(ServerlessConfig.self, from: serverlessYml)
+        let encoder = YAMLEncoder()
+        let content = try encoder.encode(serverlessConfig)
+        let data = try XCTUnwrap(content.data(using: .utf8))
+        let serverlessConfig2 = try decoder.decode(ServerlessConfig.self, from: data)
+        XCTAssertEqual(serverlessConfig, serverlessConfig2)
+    }
+    
+    func test_InitServerlessYml() throws {
+        let decoder = YAMLDecoder()
+        let serverlessYml = try fixture(name: "serverless_webhook", type: "yml")
+        let serverlessConfig2 = try decoder.decode(ServerlessConfig.self, from: serverlessYml)
+        
+        let service: String = "swift-webhook"
+        let region: Region = .us_east_1
+        let runtime: Runtime = .providedAl2
+        let architecture: Architecture = .arm64
+        let memorySize: Int = 256
+        
+        let lambdasParams: [HttpAPILambdaParams] = [
+            HttpAPILambdaParams(
+                name: "postWebHook",
+                handler: "post-webhook",
+                event: .init(path: "/webhook", method: .post),
+                environment: nil,
+                artifact: "build/WebHook/WebHook.zip"
+            ),
+            HttpAPILambdaParams(
+                name: "getWebHook",
+                handler: "get-webhook",
+                event: .init(path: "/webhook", method: .get),
+                environment: nil,
+                artifact: "build/WebHook/WebHook.zip"
+            ),
+            HttpAPILambdaParams(
+                name: "githubWebHook",
+                handler: "github-webhook",
+                event: .init(path: "/github-webhook", method: .post),
+                environment: YAMLContent.dictionary(
+                    ["WEBHOOK_SECRET": .string("${ssm:/dev/swift-webhook/webhook_secret}")]
+                ),
+                artifact: "build/GitHubWebHook/GitHubWebHook.zip"
+            )
+        ]
+        let serverlessConfig = try ServerlessConfig.webhookLambdaAPI(
+            service: service,
+            region: region,
+            runtime: runtime,
+            architecture: architecture,
+            memorySize: memorySize,
+            lambdasParams: lambdasParams
+        )
+        XCTAssertEqual(serverlessConfig, serverlessConfig2)
+    }
+}