Bug: Add Worldpay for card payments




diff --git a/Cargo.lock b/Cargo.lock
index bd50a78cc66..83398231577 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -88,7 +88,7 @@ dependencies = [
  "mime",
  "percent-encoding",
  "pin-project-lite",
- "rand",
+ "rand 0.8.5",
  "sha1",
  "smallvec",
  "tracing",
@@ -263,7 +263,7 @@ version = "0.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.8",
  "once_cell",
  "version_check",
 ]
@@ -334,6 +334,16 @@ version = "1.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f907281554a3d0312bb7aab855a8e0ef6cbf1614d06de54105039ca8b34460e"
 
+[[package]]
+name = "assert-json-diff"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
 [[package]]
 name = "async-bb8-diesel"
 version = "0.1.0"
@@ -346,6 +356,17 @@ dependencies = [
  "tokio",
 ]
 
+[[package]]
+name = "async-channel"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
+dependencies = [
+ "concurrent-queue",
+ "event-listener",
+ "futures-core",
+]
+
 [[package]]
 name = "async-stream"
 version = "0.3.3"
@@ -422,7 +443,7 @@ dependencies = [
  "mime",
  "percent-encoding",
  "pin-project-lite",
- "rand",
+ "rand 0.8.5",
  "rustls 0.20.7",
  "serde",
  "serde_json",
@@ -936,6 +957,15 @@ dependencies = [
  "time",
 ]
 
+[[package]]
+name = "concurrent-queue"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b"
+dependencies = [
+ "crossbeam-utils",
+]
+
 [[package]]
 name = "config"
 version = "0.13.3"
@@ -1069,6 +1099,25 @@ dependencies = [
  "parking_lot_core 0.9.5",
 ]
 
+[[package]]
+name = "deadpool"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "421fe0f90f2ab22016f32a9881be5134fdd71c65298917084b0c7477cbc3856e"
+dependencies = [
+ "async-trait",
+ "deadpool-runtime",
+ "num_cpus",
+ "retain_mut",
+ "tokio",
+]
+
+[[package]]
+name = "deadpool-runtime"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaa37046cc0f6c3cc6090fbdbf73ef0b8ef4cfcc37f6befc0020f63e8cf121e1"
+
 [[package]]
 name = "derive_deref"
 version = "1.1.1"
@@ -1231,13 +1280,19 @@ dependencies = [
  "rustc_version",
 ]
 
+[[package]]
+name = "event-listener"
+version = "2.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
+
 [[package]]
 name = "fake"
 version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4d68f517805463f3a896a9d29c1d6ff09d3579ded64a7201b4069f8f9c0d52fd"
 dependencies = [
- "rand",
+ "rand 0.8.5",
 ]
 
 [[package]]
@@ -1317,7 +1372,7 @@ dependencies = [
  "native-tls",
  "parking_lot 0.11.2",
  "pretty_env_logger",
- "rand",
+ "rand 0.8.5",
  "redis-protocol",
  "semver",
  "sha-1",
@@ -1442,6 +1497,21 @@ version = "0.3.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb"
 
+[[package]]
+name = "futures-lite"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48"
+dependencies = [
+ "fastrand",
+ "futures-core",
+ "futures-io",
+ "memchr",
+ "parking",
+ "pin-project-lite",
+ "waker-fn",
+]
+
 [[package]]
 name = "futures-macro"
 version = "0.3.25"
@@ -1465,6 +1535,12 @@ version = "0.3.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
 
+[[package]]
+name = "futures-timer"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
+
 [[package]]
 name = "futures-util"
 version = "0.3.25"
@@ -1503,6 +1579,17 @@ dependencies = [
  "windows",
 ]
 
+[[package]]
+name = "getrandom"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.9.0+wasi-snapshot-preview1",
+]
+
 [[package]]
 name = "getrandom"
 version = "0.2.8"
@@ -1511,7 +1598,7 @@ checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
 ]
 
 [[package]]
@@ -1625,6 +1712,27 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29"
 
+[[package]]
+name = "http-types"
+version = "2.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad"
+dependencies = [
+ "anyhow",
+ "async-channel",
+ "base64 0.13.1",
+ "futures-lite",
+ "http",
+ "infer",
+ "pin-project-lite",
+ "rand 0.7.3",
+ "serde",
+ "serde_json",
+ "serde_qs 0.8.5",
+ "serde_urlencoded",
+ "url",
+]
+
 [[package]]
 name = "httparse"
 version = "1.8.0"
@@ -1732,6 +1840,12 @@ dependencies = [
  "hashbrown",
 ]
 
+[[package]]
+name = "infer"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac"
+
 [[package]]
 name = "instant"
 version = "0.1.12"
@@ -2017,7 +2131,7 @@ checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
 dependencies = [
  "libc",
  "log",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
  "windows-sys 0.42.0",
 ]
 
@@ -2027,7 +2141,7 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8"
 dependencies = [
- "rand",
+ "rand 0.8.5",
 ]
 
 [[package]]
@@ -2231,7 +2345,7 @@ dependencies = [
  "once_cell",
  "opentelemetry_api",
  "percent-encoding",
- "rand",
+ "rand 0.8.5",
  "thiserror",
  "tokio",
  "tokio-stream",
@@ -2262,6 +2376,12 @@ dependencies = [
  "supports-color",
 ]
 
+[[package]]
+name = "parking"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
+
 [[package]]
 name = "parking_lot"
 version = "0.11.2"
@@ -2486,8 +2606,8 @@ dependencies = [
  "lazy_static",
  "num-traits",
  "quick-error 2.0.1",
- "rand",
- "rand_chacha",
+ "rand 0.8.5",
+ "rand_chacha 0.3.1",
  "rand_xorshift",
  "regex-syntax",
  "rusty-fork",
@@ -2549,6 +2669,19 @@ dependencies = [
  "scheduled-thread-pool",
 ]
 
+[[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom 0.1.16",
+ "libc",
+ "rand_chacha 0.2.2",
+ "rand_core 0.5.1",
+ "rand_hc",
+]
+
 [[package]]
 name = "rand"
 version = "0.8.5"
@@ -2556,8 +2689,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
 dependencies = [
  "libc",
- "rand_chacha",
- "rand_core",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.5.1",
 ]
 
 [[package]]
@@ -2567,7 +2710,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
 dependencies = [
  "ppv-lite86",
- "rand_core",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom 0.1.16",
 ]
 
 [[package]]
@@ -2576,7 +2728,16 @@ version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.8",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core 0.5.1",
 ]
 
 [[package]]
@@ -2585,7 +2746,7 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
 dependencies = [
- "rand_core",
+ "rand_core 0.6.4",
 ]
 
 [[package]]
@@ -2697,6 +2858,12 @@ dependencies = [
  "winreg",
 ]
 
+[[package]]
+name = "retain_mut"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4389f1d5789befaf6029ebd9f7dac4af7f7e3d61b69d4f30e2ac02b57e7712b0"
+
 [[package]]
 name = "ring"
 version = "0.16.20"
@@ -2763,7 +2930,7 @@ dependencies = [
  "nanoid",
  "num_cpus",
  "once_cell",
- "rand",
+ "rand 0.8.5",
  "redis_interface",
  "reqwest",
  "ring",
@@ -2772,8 +2939,9 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_path_to_error",
- "serde_qs",
+ "serde_qs 0.10.1",
  "serde_urlencoded",
+ "serial_test",
  "storage_models",
  "structopt",
  "strum",
@@ -2783,6 +2951,7 @@ dependencies = [
  "toml",
  "url",
  "uuid",
+ "wiremock",
 ]
 
 [[package]]
@@ -3022,6 +3191,17 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "serde_qs"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6"
+dependencies = [
+ "percent-encoding",
+ "serde",
+ "thiserror",
+]
+
 [[package]]
 name = "serde_qs"
 version = "0.10.1"
@@ -3045,6 +3225,31 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "serial_test"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c789ec87f4687d022a2405cf46e0cd6284889f1839de292cadeb6c6019506f2"
+dependencies = [
+ "dashmap",
+ "futures",
+ "lazy_static",
+ "log",
+ "parking_lot 0.12.1",
+ "serial_test_derive",
+]
+
+[[package]]
+name = "serial_test_derive"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b64f9e531ce97c88b4778aad0ceee079216071cffec6ac9b904277f8f92e7fe3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "sha-1"
 version = "0.9.8"
@@ -3506,7 +3711,7 @@ dependencies = [
  "indexmap",
  "pin-project",
  "pin-project-lite",
- "rand",
+ "rand 0.8.5",
  "slab",
  "tokio",
  "tokio-util 0.7.4",
@@ -3752,7 +3957,7 @@ version = "1.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
 dependencies = [
- "getrandom",
+ "getrandom 0.2.8",
  "serde",
 ]
 
@@ -3807,6 +4012,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "waker-fn"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
+
 [[package]]
 name = "want"
 version = "0.3.0"
@@ -3817,6 +4028,12 @@ dependencies = [
  "try-lock",
 ]
 
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
@@ -4083,6 +4300,28 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "wiremock"
+version = "0.5.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "249dc68542861d17eae4b4e5e8fb381c2f9e8f255a84f6771d5fdf8b6c03ce3c"
+dependencies = [
+ "assert-json-diff",
+ "async-trait",
+ "base64 0.13.1",
+ "deadpool",
+ "futures",
+ "futures-timer",
+ "http-types",
+ "hyper",
+ "log",
+ "once_cell",
+ "regex",
+ "serde",
+ "serde_json",
+ "tokio",
+]
+
 [[package]]
 name = "xmlparser"
 version = "0.13.3"
diff --git a/add_connector.md b/add_connector.md
index 14868530fb0..90837ce6ccf 100644
--- a/add_connector.md
+++ b/add_connector.md
@@ -45,36 +45,29 @@ Below is a step-by-step tutorial for integrating a new connector.
 
 ### **Generate the template**
 
-Install cargo generate.
-
-```bash
-cargo install cargo-generate
-```
-
-Under `crates/router/src/connector/` run the following commands
-
 ```bash
-cargo gen-pg <connector-name>
+cd scripts
+sh add_connector.sh <connector-name>
 ```
 
 For this tutorial `<connector-name>` would be `checkout`.
 
-The folder structure will be modified this way
-
-![directory image](/docs/imgs/connector-layout.png)
+The folder structure will be modified as below
+```
+crates/router/src/connector
+├── checkout
+│   └── transformers.rs
+└── checkout.rs
+crates/router/tests/connectors
+└── checkout.rs
+```
 
-`transformers.rs` will contain connectors API Request and Response types, and conversion between the router and connector API types.
-`mod.rs` will contain the trait implementations for the connector.
+`crates/router/src/connector/checkout/transformers.rs` will contain connectors API Request and Response types, and conversion between the router and connector API types.
+`crates/router/src/connector/checkout.rs` will contain the trait implementations for the connector.
+`crates/router/tests/connectors/checkout.rs` will contain the basic tests for the payments flows.
 
 There is boiler plate code with `todo!()` in the above mentioned files. Go through the rest of the guide and fill in code wherever necessary.
 
-Add the below lines in `src/connector/mod.rs`
-
-```rust
-pub mod checkout;
-pub use checkout::Checkout;
-```
-
 ### **Implementing Request and Response types**
 
 Adding new Connector is all about implementing the data transformation from Router's core to Connector's API request format.
@@ -287,13 +280,64 @@ Don’t forget to add logs lines in appropriate places.
 Refer to other conector code for trait implementations. mostly tThe rust compiler will guide you to do it easily.
 Feel free to connect with us in case of any queries and if you want to confirm the status mapping.
 
-Feel free to connect with us in case of queries and also if you want to confirm the status mapping.
+### **Test the connector**
+Try running the tests in `crates/router/tests/connectors/{{connector-name}}.rs`.
+All tests should pass and add appropiate tests for connector specific payment flows.
+
+### **Build payment request and response from json schema**
+Some connectors will provide [json schema](https://developer.worldpay.com/docs/access-worldpay/api/references/payments) for each request and response supported. We can directly convert that schema to rust code by using below script. On running the script a `temp.rs` file will be created in `src/connector/<connector-name>` folder
 
-### After implementing the above
+*Note: The code generated may not be production ready and might fail for some case, we have to clean up the code as per our standards.*
 
-Add connector name in :
+```bash
+brew install openapi-generator
+export CONNECTOR_NAME="<CONNECTOR-NAME>" #Change it to appropriate connector name
+export SCHEMA_PATH="<PATH-TO-JSON-SCHEMA-FILE>" #it can be json or yaml, Refer samples below
+openapi-generator generate -g rust  -i ${SCHEMA_PATH} -o temp &&  cat temp/src/models/* > crates/router/src/connector/${CONNECTOR_NAME}/temp.rs && rm -rf temp && sed -i'' -r "s/^pub use.*//;s/^pub mod.*//;s/^\/.*//;s/^.\*.*//;s/crate::models:://g;" crates/router/src/connector/${CONNECTOR_NAME}/temp.rs && cargo +nightly fmt
+```
 
-- `crates/api_models/src/enums.rs` in Connector enum (in alphabetical order)
-- `crates/router/src/types/api/mod.rs` convert_connector function
+JSON example
+```json
+{
+    "openapi": "3.0.1",
+    "paths": {},
+    "info": {
+        "title": "",
+        "version": ""
+    },
+    "components": {
+        "schemas": {
+            "PaymentsResponse": {
+                "type": "object",
+                "properties": {
+                    "outcome": {
+                        "type": "string"
+                    }
+                },
+                "required": [
+                    "outcome"
+                ]
+            }
+        }
+    }
+}
+```
 
-Configure the Connectors API credentials using the PaymentConnectors API.
+YAML example
+```yaml
+---
+openapi: 3.0.1
+paths: {}
+info:
+  title: ""
+  version: ""
+components:
+  schemas:
+    PaymentsResponse:
+        type: object
+        properties:
+            outcome:
+              type: string
+        required:
+            - outcome
+```
diff --git a/config/Development.toml b/config/Development.toml
index b80cba72e90..456311468b3 100644
--- a/config/Development.toml
+++ b/config/Development.toml
@@ -38,7 +38,7 @@ locker_decryption_key2 = ""
 
 [connectors.supported]
 wallets = ["klarna", "braintree", "applepay"]
-cards = ["stripe", "adyen", "authorizedotnet", "checkout", "braintree", "aci", "shift4", "cybersource"]
+cards = ["stripe", "adyen", "authorizedotnet", "checkout", "braintree", "aci", "shift4", "cybersource", "worldpay"]
 
 [eph_key]
 validity = 1
@@ -73,6 +73,9 @@ base_url = "https://apitest.cybersource.com/"
 [connectors.shift4]
 base_url = "https://api.shift4.com/"
 
+[connectors.worldpay]
+base_url = "http://localhost:9090/"
+
 [scheduler]
 stream = "SCHEDULER_STREAM"
 consumer_group = "SCHEDULER_GROUP"
diff --git a/config/config.example.toml b/config/config.example.toml
index 8487c71440c..8f8b607f7be 100644
--- a/config/config.example.toml
+++ b/config/config.example.toml
@@ -125,6 +125,9 @@ base_url = "https://apitest.cybersource.com/"
 [connectors.shift4]
 base_url = "https://api.shift4.com/"
 
+[connectors.worldpay]
+base_url = "https://try.access.worldpay.com/"
+
 # This data is used to call respective connectors for wallets and cards
 [connectors.supported]
 wallets = ["klarna", "braintree", "applepay"]
diff --git a/config/docker_compose.toml b/config/docker_compose.toml
index 26b72c0a2f0..1be7c770bd0 100644
--- a/config/docker_compose.toml
+++ b/config/docker_compose.toml
@@ -80,6 +80,9 @@ base_url = "https://apitest.cybersource.com/"
 [connectors.shift4]
 base_url = "https://api.shift4.com/"
 
+[connectors.worldpay]
+base_url = "https://try.access.worldpay.com/"
+
 [connectors.supported]
 wallets = ["klarna", "braintree", "applepay"]
-cards = ["stripe", "adyen", "authorizedotnet", "checkout", "braintree", "shift4", "cybersource"]
+cards = ["stripe", "adyen", "authorizedotnet", "checkout", "braintree", "shift4", "cybersource", "worldpay"]
diff --git a/connector-template/mod.rs b/connector-template/mod.rs
index 4cf6645993a..4081b1b72b3 100644
--- a/connector-template/mod.rs
+++ b/connector-template/mod.rs
@@ -3,7 +3,7 @@ mod transformers;
 use std::fmt::Debug;
 
 use bytes::Bytes;
-use error_stack::ResultExt;
+use error_stack::{ResultExt, IntoReport};
 
 use crate::{
     configs::settings,
@@ -12,7 +12,7 @@ use crate::{
         errors::{self, CustomResult},
         payments,
     },
-    headers, logger, services,
+    headers, logger, services::{self, ConnectorIntegration},
     types::{
         self,
         api::{self, ConnectorCommon, ConnectorCommonExt},
@@ -26,16 +26,19 @@ use transformers as {{project-name | downcase}};
 #[derive(Debug, Clone)]
 pub struct {{project-name | downcase | pascal_case}};
 
-impl api::ConnectorCommonExt for {{project-name | downcase | pascal_case}} {
-    fn build_headers<Flow, Request, Response>(
+impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for {{project-name | downcase | pascal_case}} 
+where
+    Self: ConnectorIntegration<Flow, Request, Response>,{
+    fn build_headers(
         &self,
-        req: &types::RouterData<Flow, Request, Response>,
+        _req: &types::RouterData<Flow, Request, Response>,
+        _connectors: &settings::Connectors,
     ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
         todo!()
     }
 }
 
-impl api::ConnectorCommon for {{project-name | downcase | pascal_case}} {
+impl ConnectorCommon for {{project-name | downcase | pascal_case}} {
     fn id(&self) -> &'static str {
         "{{project-name | downcase}}"
     }
@@ -58,7 +61,7 @@ impl api::Payment for {{project-name | downcase | pascal_case}} {}
 
 impl api::PreVerify for {{project-name | downcase | pascal_case}} {}
 impl
-    services::ConnectorIntegration<
+    ConnectorIntegration<
         api::Verify,
         types::VerifyRequestData,
         types::PaymentsResponseData,
@@ -69,7 +72,7 @@ impl
 impl api::PaymentVoid for {{project-name | downcase | pascal_case}} {}
 
 impl
-    services::ConnectorIntegration<
+    ConnectorIntegration<
         api::Void,
         types::PaymentsCancelData,
         types::PaymentsResponseData,
@@ -78,12 +81,13 @@ impl
 
 impl api::PaymentSync for {{project-name | downcase | pascal_case}} {}
 impl
-    services::ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
+    ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
     for {{project-name | downcase | pascal_case}}
 {
     fn get_headers(
         &self,
-        req: &types::PaymentsSyncRouterData,
+        _req: &types::PaymentsSyncRouterData,
+        _connectors: &settings::Connectors,
     ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
         todo!()
     }
@@ -94,31 +98,31 @@ impl
 
     fn get_url(
         &self,
-        req: &types::PaymentsSyncRouterData,
-        connectors: &settings::Connectors,
+        _req: &types::PaymentsSyncRouterData,
+        _connectors: &settings::Connectors,
     ) -> CustomResult<String, errors::ConnectorError> {
         todo!()
     }
 
     fn build_request(
         &self,
-        req: &types::PaymentsSyncRouterData,
-        connectors: &settings::Connectors,
+        _req: &types::PaymentsSyncRouterData,
+        _connectors: &settings::Connectors,
     ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
         todo!()
     }
 
     fn get_error_response(
         &self,
-        res: Bytes,
+        _res: Bytes,
     ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
         todo!()
     }
 
     fn handle_response(
         &self,
-        data: &types::PaymentsSyncRouterData,
-        res: Response,
+        _data: &types::PaymentsSyncRouterData,
+        _res: Response,
     ) -> CustomResult<types::PaymentsSyncRouterData, errors::ConnectorError> {
         todo!()
     }
@@ -127,7 +131,7 @@ impl
 
 impl api::PaymentCapture for {{project-name | downcase | pascal_case}} {}
 impl
-    services::ConnectorIntegration<
+    ConnectorIntegration<
         api::Capture,
         types::PaymentsCaptureData,
         types::PaymentsResponseData,
@@ -135,7 +139,8 @@ impl
 {
     fn get_headers(
         &self,
-        req: &types::PaymentsCaptureRouterData,
+        _req: &types::PaymentsCaptureRouterData,
+        _connectors: &settings::Connectors,
     ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
         todo!()
     }
@@ -153,31 +158,31 @@ impl
 
     fn build_request(
         &self,
-        req: &types::PaymentsCaptureRouterData,
-        connectors: &settings::Connectors,
+        _req: &types::PaymentsCaptureRouterData,
+        _connectors: &settings::Connectors,
     ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
         todo!()
     }
 
     fn handle_response(
         &self,
-        data: &types::PaymentsCaptureRouterData,
-        res: Response,
+        _data: &types::PaymentsCaptureRouterData,
+        _res: Response,
     ) -> CustomResult<types::PaymentsCaptureRouterData, errors::ConnectorError> {
         todo!()
     }
 
     fn get_url(
         &self,
-        req: &types::PaymentsCaptureRouterData,
-        connectors: &settings::Connectors,
+        _req: &types::PaymentsCaptureRouterData,
+        _connectors: &settings::Connectors,
     ) -> CustomResult<String, errors::ConnectorError> {
         todo!()
     }
 
     fn get_error_response(
         &self,
-        res: Bytes,
+        _res: Bytes,
     ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
         todo!()
     }
@@ -186,7 +191,7 @@ impl
 impl api::PaymentSession for {{project-name | downcase | pascal_case}} {}
 
 impl
-    services::ConnectorIntegration<
+    ConnectorIntegration<
         api::Session,
         types::PaymentsSessionData,
         types::PaymentsResponseData,
@@ -198,12 +203,12 @@ impl
 impl api::PaymentAuthorize for {{project-name | downcase | pascal_case}} {}
 
 impl
-    services::ConnectorIntegration<
+    ConnectorIntegration<
         api::Authorize,
         types::PaymentsAuthorizeData,
         types::PaymentsResponseData,
     > for {{project-name | downcase | pascal_case}} {
-    fn get_headers(&self, _req: &types::PaymentsAuthorizeRouterData) -> CustomResult<Vec<(String, String)>,errors::ConnectorError> {
+    fn get_headers(&self, _req: &types::PaymentsAuthorizeRouterData,_connectors: &settings::Connectors,) -> CustomResult<Vec<(String, String)>,errors::ConnectorError> {
         todo!()
     }
 
@@ -211,13 +216,13 @@ impl
         todo!()
     }
 
-    fn get_url(&self, _req: &types::PaymentsAuthorizeRouterData, connectors: &settings::Connectors,) -> CustomResult<String,errors::ConnectorError> {
+    fn get_url(&self, _req: &types::PaymentsAuthorizeRouterData, _connectors: &settings::Connectors,) -> CustomResult<String,errors::ConnectorError> {
         todo!()
     }
 
     fn get_request_body(&self, req: &types::PaymentsAuthorizeRouterData) -> CustomResult<Option<String>,errors::ConnectorError> {
         let {{project-name | downcase}}_req =
-            utils::Encode::<{{project-name | downcase}}::{{project-name | downcase | pascal_case}}PaymentsRequest>::convert_and_url_encode(req).change_context(errors::ConnectorError::RequestEncodingFailed)?;
+            utils::Encode::<{{project-name | downcase}}::{{project-name | downcase | pascal_case}}PaymentsRequest>::convert_and_encode(req).change_context(errors::ConnectorError::RequestEncodingFailed)?;
         Ok(Some({{project-name | downcase}}_req))
     }
 
@@ -247,12 +252,12 @@ impl api::RefundExecute for {{project-name | downcase | pascal_case}} {}
 impl api::RefundSync for {{project-name | downcase | pascal_case}} {}
 
 impl
-    services::ConnectorIntegration<
+    ConnectorIntegration<
         api::Execute,
         types::RefundsData,
         types::RefundsResponseData,
     > for {{project-name | downcase | pascal_case}} {
-    fn get_headers(&self, _req: &types::RefundsRouterData<api::Execute>) -> CustomResult<Vec<(String,String)>,errors::ConnectorError> {
+    fn get_headers(&self, _req: &types::RefundsRouterData<api::Execute>,_connectors: &settings::Connectors,) -> CustomResult<Vec<(String,String)>,errors::ConnectorError> {
         todo!()
     }
 
@@ -260,12 +265,12 @@ impl
         todo!()
     }
 
-    fn get_url(&self, _req: &types::RefundsRouterData<api::Execute>, connectors: &settings::Connectors,) -> CustomResult<String,errors::ConnectorError> {
+    fn get_url(&self, _req: &types::RefundsRouterData<api::Execute>, _connectors: &settings::Connectors,) -> CustomResult<String,errors::ConnectorError> {
         todo!()
     }
 
     fn get_request_body(&self, req: &types::RefundsRouterData<api::Execute>) -> CustomResult<Option<String>,errors::ConnectorError> {
-        let {{project-name | downcase}}_req = utils::Encode::<{{project-name| downcase}}::{{project-name | downcase | pascal_case}}RefundRequest>::convert_and_url_encode(req).change_context(errors::ConnectorError::RequestEncodingFailed)?;
+        let {{project-name | downcase}}_req = utils::Encode::<{{project-name| downcase}}::{{project-name | downcase | pascal_case}}RefundRequest>::convert_and_encode(req).change_context(errors::ConnectorError::RequestEncodingFailed)?;
         Ok(Some({{project-name | downcase}}_req))
     }
 
@@ -273,7 +278,7 @@ impl
         let request = services::RequestBuilder::new()
             .method(services::Method::Post)
             .url(&types::RefundExecuteType::get_url(self, req, connectors)?)
-            .headers(types::RefundExecuteType::get_headers(self, req)?)
+            .headers(types::RefundExecuteType::get_headers(self, req, connectors)?)
             .body(types::RefundExecuteType::get_request_body(self, req)?)
             .build();
         Ok(Some(request))
@@ -301,8 +306,8 @@ impl
 }
 
 impl
-    services::ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData> for {{project-name | downcase | pascal_case}} {
-    fn get_headers(&self, _req: &types::RefundSyncRouterData) -> CustomResult<Vec<(String, String)>,errors::ConnectorError> {
+    ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData> for {{project-name | downcase | pascal_case}} {
+    fn get_headers(&self, _req: &types::RefundSyncRouterData,_connectors: &settings::Connectors,) -> CustomResult<Vec<(String, String)>,errors::ConnectorError> {
         todo!()
     }
 
@@ -341,21 +346,21 @@ impl api::IncomingWebhook for {{project-name | downcase | pascal_case}} {
         &self,
         _body: &[u8],
     ) -> CustomResult<String, errors::ConnectorError> {
-        todo!()
+        Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
     }
 
     fn get_webhook_event_type(
         &self,
         _body: &[u8],
     ) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
-        todo!()
+        Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
     }
 
     fn get_webhook_resource_object(
         &self,
         _body: &[u8],
     ) -> CustomResult<serde_json::Value, errors::ConnectorError> {
-        todo!()
+        Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
     }
 }
 
diff --git a/connector-template/test.rs b/connector-template/test.rs
index 1ba4de5e6f5..a5d8a15e1ca 100644
--- a/connector-template/test.rs
+++ b/connector-template/test.rs
@@ -8,7 +8,7 @@ use crate::{
 };
 
 struct {{project-name | downcase | pascal_case}};
-impl utils::ConnectorActions for {{project-name | downcase | pascal_case}} {}
+impl ConnectorActions for {{project-name | downcase | pascal_case}} {}
 impl utils::Connector for {{project-name | downcase | pascal_case}} {
     fn get_data(&self) -> types::api::ConnectorData {
         use router::connector::{{project-name | downcase | pascal_case}};
diff --git a/crates/api_models/src/enums.rs b/crates/api_models/src/enums.rs
index 48c5a32a9d2..459fb30a6d5 100644
--- a/crates/api_models/src/enums.rs
+++ b/crates/api_models/src/enums.rs
@@ -497,6 +497,7 @@ pub enum Connector {
     Klarna,
     Shift4,
     Stripe,
+    Worldpay,
 }
 
 impl From<AttemptStatus> for IntentStatus {
diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml
index e65decd6dbe..511fbab78c8 100644
--- a/crates/router/Cargo.toml
+++ b/crates/router/Cargo.toml
@@ -87,6 +87,8 @@ rand = "0.8.5"
 time = { version = "0.3.17", features = ["macros"] }
 tokio = "1.23.0"
 toml = "0.5.9"
+serial_test = "0.10.0"
+wiremock = "0.5"
 
 [[bin]]
 name = "router"
diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs
index f5e8e744318..872512ded50 100644
--- a/crates/router/src/configs/settings.rs
+++ b/crates/router/src/configs/settings.rs
@@ -117,6 +117,7 @@ pub struct Connectors {
     pub shift4: ConnectorParams,
     pub stripe: ConnectorParams,
     pub supported: SupportedConnectors,
+    pub worldpay: ConnectorParams,
     pub applepay: ConnectorParams,
 }
 
diff --git a/crates/router/src/connector.rs b/crates/router/src/connector.rs
index 9b598df8f34..af3f33990e5 100644
--- a/crates/router/src/connector.rs
+++ b/crates/router/src/connector.rs
@@ -6,12 +6,12 @@ pub mod braintree;
 pub mod checkout;
 pub mod cybersource;
 pub mod klarna;
-pub mod stripe;
-
 pub mod shift4;
+pub mod stripe;
+pub mod worldpay;
 
 pub use self::{
     aci::Aci, adyen::Adyen, applepay::Applepay, authorizedotnet::Authorizedotnet,
     braintree::Braintree, checkout::Checkout, cybersource::Cybersource, klarna::Klarna,
-    shift4::Shift4, stripe::Stripe,
+    shift4::Shift4, stripe::Stripe, worldpay::Worldpay,
 };
diff --git a/crates/router/src/connector/shift4.rs b/crates/router/src/connector/shift4.rs
index 312a525910a..3f76f0aef61 100644
--- a/crates/router/src/connector/shift4.rs
+++ b/crates/router/src/connector/shift4.rs
@@ -439,6 +439,21 @@ impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponse
         Ok(format!("{}refunds", self.base_url(connectors),))
     }
 
+    fn build_request(
+        &self,
+        req: &types::RefundSyncRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        Ok(Some(
+            services::RequestBuilder::new()
+                .method(services::Method::Get)
+                .url(&types::RefundSyncType::get_url(self, req, connectors)?)
+                .headers(types::RefundSyncType::get_headers(self, req, connectors)?)
+                .body(types::RefundSyncType::get_request_body(self, req)?)
+                .build(),
+        ))
+    }
+
     fn handle_response(
         &self,
         data: &types::RefundSyncRouterData,
diff --git a/crates/router/src/connector/worldpay.rs b/crates/router/src/connector/worldpay.rs
new file mode 100644
index 00000000000..e2d9741e9d0
--- /dev/null
+++ b/crates/router/src/connector/worldpay.rs
@@ -0,0 +1,613 @@
+mod requests;
+mod response;
+mod transformers;
+
+use std::fmt::Debug;
+
+use bytes::Bytes;
+use error_stack::{IntoReport, ResultExt};
+use storage_models::enums;
+use transformers as worldpay;
+
+use self::{requests::*, response::*};
+use crate::{
+    configs::settings,
+    core::{
+        errors::{self, CustomResult},
+        payments,
+    },
+    headers, logger,
+    services::{self, ConnectorIntegration},
+    types::{
+        self,
+        api::{self, ConnectorCommon, ConnectorCommonExt},
+        ErrorResponse, Response,
+    },
+    utils::{self, BytesExt},
+};
+
+#[derive(Debug, Clone)]
+pub struct Worldpay;
+
+impl<Flow, Request, Response> ConnectorCommonExt<Flow, Request, Response> for Worldpay
+where
+    Self: ConnectorIntegration<Flow, Request, Response>,
+{
+    fn build_headers(
+        &self,
+        req: &types::RouterData<Flow, Request, Response>,
+        _connectors: &settings::Connectors,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        let mut headers = vec![(
+            headers::CONTENT_TYPE.to_string(),
+            self.get_content_type().to_string(),
+        )];
+        let mut api_key = self.get_auth_header(&req.connector_auth_type)?;
+        headers.append(&mut api_key);
+        Ok(headers)
+    }
+}
+
+impl ConnectorCommon for Worldpay {
+    fn id(&self) -> &'static str {
+        "worldpay"
+    }
+
+    fn common_get_content_type(&self) -> &'static str {
+        "application/vnd.worldpay.payments-v6+json"
+    }
+
+    fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str {
+        connectors.worldpay.base_url.as_ref()
+    }
+
+    fn get_auth_header(
+        &self,
+        auth_type: &types::ConnectorAuthType,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        let auth: worldpay::WorldpayAuthType = auth_type
+            .try_into()
+            .change_context(errors::ConnectorError::FailedToObtainAuthType)?;
+        Ok(vec![(headers::AUTHORIZATION.to_string(), auth.api_key)])
+    }
+
+    fn build_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        let response: WorldpayErrorResponse = res
+            .parse_struct("WorldpayErrorResponse")
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+        Ok(ErrorResponse {
+            code: response.error_name,
+            message: response.message,
+            reason: None,
+        })
+    }
+}
+
+impl api::Payment for Worldpay {}
+
+impl api::PreVerify for Worldpay {}
+impl ConnectorIntegration<api::Verify, types::VerifyRequestData, types::PaymentsResponseData>
+    for Worldpay
+{
+}
+
+impl api::PaymentVoid for Worldpay {}
+
+impl ConnectorIntegration<api::Void, types::PaymentsCancelData, types::PaymentsResponseData>
+    for Worldpay
+{
+    fn get_headers(
+        &self,
+        req: &types::PaymentsCancelRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        self.build_headers(req, connectors)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn get_url(
+        &self,
+        req: &types::PaymentsCancelRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        let connector_payment_id = req.request.connector_transaction_id.clone();
+        Ok(format!(
+            "{}payments/settlements/{}",
+            self.base_url(connectors),
+            connector_payment_id
+        ))
+    }
+
+    fn build_request(
+        &self,
+        req: &types::PaymentsCancelRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        Ok(Some(
+            services::RequestBuilder::new()
+                .method(services::Method::Post)
+                .url(&types::PaymentsVoidType::get_url(self, req, connectors)?)
+                .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?)
+                .build(),
+        ))
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::PaymentsCancelRouterData,
+        res: Response,
+    ) -> CustomResult<types::PaymentsCancelRouterData, errors::ConnectorError>
+    where
+        api::Void: Clone,
+        types::PaymentsCancelData: Clone,
+        types::PaymentsResponseData: Clone,
+    {
+        match res.status_code {
+            202 => {
+                let response: WorldpayPaymentsResponse = res
+                    .response
+                    .parse_struct("Worldpay PaymentsResponse")
+                    .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+                Ok(types::PaymentsCancelRouterData {
+                    status: enums::AttemptStatus::Voided,
+                    response: Ok(types::PaymentsResponseData::TransactionResponse {
+                        resource_id: types::ResponseId::try_from(response.links)?,
+                        redirection_data: None,
+                        redirect: false,
+                        mandate_reference: None,
+                    }),
+                    ..data.clone()
+                })
+            }
+            _ => Err(errors::ConnectorError::ResponseHandlingFailed)?,
+        }
+    }
+
+    fn get_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res)
+    }
+}
+
+impl api::PaymentSync for Worldpay {}
+impl ConnectorIntegration<api::PSync, types::PaymentsSyncData, types::PaymentsResponseData>
+    for Worldpay
+{
+    fn get_headers(
+        &self,
+        req: &types::PaymentsSyncRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        self.build_headers(req, connectors)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn get_url(
+        &self,
+        req: &types::PaymentsSyncRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        let connector_payment_id = req
+            .request
+            .connector_transaction_id
+            .get_connector_transaction_id()
+            .change_context(errors::ConnectorError::MissingConnectorTransactionID)?;
+        Ok(format!(
+            "{}payments/events/{}",
+            self.base_url(connectors),
+            connector_payment_id
+        ))
+    }
+
+    fn build_request(
+        &self,
+        req: &types::PaymentsSyncRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        Ok(Some(
+            services::RequestBuilder::new()
+                .method(services::Method::Get)
+                .url(&types::PaymentsSyncType::get_url(self, req, connectors)?)
+                .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?)
+                .body(types::PaymentsSyncType::get_request_body(self, req)?)
+                .build(),
+        ))
+    }
+
+    fn get_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res)
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::PaymentsSyncRouterData,
+        res: Response,
+    ) -> CustomResult<types::PaymentsSyncRouterData, errors::ConnectorError> {
+        let response: WorldpayEventResponse =
+            res.response
+                .parse_struct("Worldpay EventResponse")
+                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+
+        Ok(types::PaymentsSyncRouterData {
+            status: enums::AttemptStatus::from(response.last_event),
+            response: Ok(types::PaymentsResponseData::TransactionResponse {
+                resource_id: data.request.connector_transaction_id.clone(),
+                redirection_data: None,
+                redirect: false,
+                mandate_reference: None,
+            }),
+            ..data.clone()
+        })
+    }
+}
+
+impl api::PaymentCapture for Worldpay {}
+impl ConnectorIntegration<api::Capture, types::PaymentsCaptureData, types::PaymentsResponseData>
+    for Worldpay
+{
+    fn get_headers(
+        &self,
+        req: &types::PaymentsCaptureRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        self.build_headers(req, connectors)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn build_request(
+        &self,
+        req: &types::PaymentsCaptureRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        Ok(Some(
+            services::RequestBuilder::new()
+                .method(services::Method::Post)
+                .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?)
+                .headers(types::PaymentsCaptureType::get_headers(
+                    self, req, connectors,
+                )?)
+                .build(),
+        ))
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::PaymentsCaptureRouterData,
+        res: Response,
+    ) -> CustomResult<types::PaymentsCaptureRouterData, errors::ConnectorError> {
+        logger::debug!(worldpaypayments_capture_response=?res);
+        match res.status_code {
+            202 => {
+                let response: WorldpayPaymentsResponse = res
+                    .response
+                    .parse_struct("Worldpay PaymentsResponse")
+                    .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+                Ok(types::PaymentsCaptureRouterData {
+                    status: enums::AttemptStatus::Charged,
+                    response: Ok(types::PaymentsResponseData::TransactionResponse {
+                        resource_id: types::ResponseId::try_from(response.links)?,
+                        redirection_data: None,
+                        redirect: false,
+                        mandate_reference: None,
+                    }),
+                    ..data.clone()
+                })
+            }
+            _ => Err(errors::ConnectorError::ResponseHandlingFailed)?,
+        }
+    }
+
+    fn get_url(
+        &self,
+        req: &types::PaymentsCaptureRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        let connector_payment_id = req.request.connector_transaction_id.clone();
+        Ok(format!(
+            "{}payments/settlements/{}",
+            self.base_url(connectors),
+            connector_payment_id
+        ))
+    }
+
+    fn get_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res)
+    }
+}
+
+impl api::PaymentSession for Worldpay {}
+
+impl ConnectorIntegration<api::Session, types::PaymentsSessionData, types::PaymentsResponseData>
+    for Worldpay
+{
+}
+
+impl api::PaymentAuthorize for Worldpay {}
+
+impl ConnectorIntegration<api::Authorize, types::PaymentsAuthorizeData, types::PaymentsResponseData>
+    for Worldpay
+{
+    fn get_headers(
+        &self,
+        req: &types::PaymentsAuthorizeRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        self.build_headers(req, connectors)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn get_url(
+        &self,
+        _req: &types::PaymentsAuthorizeRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Ok(format!(
+            "{}payments/authorizations",
+            self.base_url(connectors)
+        ))
+    }
+
+    fn get_request_body(
+        &self,
+        req: &types::PaymentsAuthorizeRouterData,
+    ) -> CustomResult<Option<String>, errors::ConnectorError> {
+        let worldpay_req = utils::Encode::<WorldpayPaymentsRequest>::convert_and_encode(req)
+            .change_context(errors::ConnectorError::RequestEncodingFailed)?;
+        Ok(Some(worldpay_req))
+    }
+
+    fn build_request(
+        &self,
+        req: &types::PaymentsAuthorizeRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        Ok(Some(
+            services::RequestBuilder::new()
+                .method(services::Method::Post)
+                .url(&types::PaymentsAuthorizeType::get_url(
+                    self, req, connectors,
+                )?)
+                .headers(types::PaymentsAuthorizeType::get_headers(
+                    self, req, connectors,
+                )?)
+                .body(types::PaymentsAuthorizeType::get_request_body(self, req)?)
+                .build(),
+        ))
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::PaymentsAuthorizeRouterData,
+        res: Response,
+    ) -> CustomResult<types::PaymentsAuthorizeRouterData, errors::ConnectorError> {
+        let response: WorldpayPaymentsResponse = res
+            .response
+            .parse_struct("Worldpay PaymentsResponse")
+            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+        logger::debug!(worldpaypayments_create_response=?response);
+        types::RouterData::try_from(types::ResponseRouterData {
+            response,
+            data: data.clone(),
+            http_code: res.status_code,
+        })
+        .change_context(errors::ConnectorError::ResponseHandlingFailed)
+    }
+
+    fn get_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res)
+    }
+}
+
+impl api::Refund for Worldpay {}
+impl api::RefundExecute for Worldpay {}
+impl api::RefundSync for Worldpay {}
+
+impl ConnectorIntegration<api::Execute, types::RefundsData, types::RefundsResponseData>
+    for Worldpay
+{
+    fn get_headers(
+        &self,
+        req: &types::RefundsRouterData<api::Execute>,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        self.build_headers(req, connectors)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn get_request_body(
+        &self,
+        req: &types::RefundExecuteRouterData,
+    ) -> CustomResult<Option<String>, errors::ConnectorError> {
+        let req = utils::Encode::<WorldpayRefundRequest>::convert_and_encode(req)
+            .change_context(errors::ConnectorError::RequestEncodingFailed)?;
+        Ok(Some(req))
+    }
+
+    fn get_url(
+        &self,
+        req: &types::RefundsRouterData<api::Execute>,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        let connector_payment_id = req.request.connector_transaction_id.clone();
+        Ok(format!(
+            "{}payments/settlements/refunds/partials/{}",
+            self.base_url(connectors),
+            connector_payment_id
+        ))
+    }
+
+    fn build_request(
+        &self,
+        req: &types::RefundsRouterData<api::Execute>,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        let request = services::RequestBuilder::new()
+            .method(services::Method::Post)
+            .url(&types::RefundExecuteType::get_url(self, req, connectors)?)
+            .headers(types::RefundExecuteType::get_headers(
+                self, req, connectors,
+            )?)
+            .body(types::RefundExecuteType::get_request_body(self, req)?)
+            .build();
+        Ok(Some(request))
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::RefundsRouterData<api::Execute>,
+        res: Response,
+    ) -> CustomResult<types::RefundsRouterData<api::Execute>, errors::ConnectorError> {
+        logger::debug!(target: "router::connector::worldpay", response=?res);
+        match res.status_code {
+            202 => {
+                let response: WorldpayPaymentsResponse = res
+                    .response
+                    .parse_struct("Worldpay PaymentsResponse")
+                    .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+                Ok(types::RefundExecuteRouterData {
+                    response: Ok(types::RefundsResponseData {
+                        connector_refund_id: ResponseIdStr::try_from(response.links)?.id,
+                        refund_status: enums::RefundStatus::Success,
+                    }),
+                    ..data.clone()
+                })
+            }
+            _ => Err(errors::ConnectorError::ResponseHandlingFailed)?,
+        }
+    }
+
+    fn get_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res)
+    }
+}
+
+impl ConnectorIntegration<api::RSync, types::RefundsData, types::RefundsResponseData> for Worldpay {
+    fn get_headers(
+        &self,
+        req: &types::RefundSyncRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Vec<(String, String)>, errors::ConnectorError> {
+        self.build_headers(req, connectors)
+    }
+
+    fn get_content_type(&self) -> &'static str {
+        self.common_get_content_type()
+    }
+
+    fn get_url(
+        &self,
+        req: &types::RefundSyncRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Ok(format!(
+            "{}payments/events/{}",
+            self.base_url(connectors),
+            req.request.connector_transaction_id
+        ))
+    }
+
+    fn build_request(
+        &self,
+        req: &types::RefundSyncRouterData,
+        connectors: &settings::Connectors,
+    ) -> CustomResult<Option<services::Request>, errors::ConnectorError> {
+        Ok(Some(
+            services::RequestBuilder::new()
+                .method(services::Method::Get)
+                .url(&types::RefundSyncType::get_url(self, req, connectors)?)
+                .headers(types::RefundSyncType::get_headers(self, req, connectors)?)
+                .body(types::RefundSyncType::get_request_body(self, req)?)
+                .build(),
+        ))
+    }
+
+    fn handle_response(
+        &self,
+        data: &types::RefundSyncRouterData,
+        res: Response,
+    ) -> CustomResult<types::RefundSyncRouterData, errors::ConnectorError> {
+        let response: WorldpayEventResponse =
+            res.response
+                .parse_struct("Worldpay EventResponse")
+                .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;
+        Ok(types::RefundSyncRouterData {
+            response: Ok(types::RefundsResponseData {
+                connector_refund_id: data.request.refund_id.clone(),
+                refund_status: enums::RefundStatus::from(response.last_event),
+            }),
+            ..data.clone()
+        })
+    }
+
+    fn get_error_response(
+        &self,
+        res: Bytes,
+    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
+        self.build_error_response(res)
+    }
+}
+
+#[async_trait::async_trait]
+impl api::IncomingWebhook for Worldpay {
+    fn get_webhook_object_reference_id(
+        &self,
+        _body: &[u8],
+    ) -> CustomResult<String, errors::ConnectorError> {
+        Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
+    }
+
+    fn get_webhook_event_type(
+        &self,
+        _body: &[u8],
+    ) -> CustomResult<api::IncomingWebhookEvent, errors::ConnectorError> {
+        Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
+    }
+
+    fn get_webhook_resource_object(
+        &self,
+        _body: &[u8],
+    ) -> CustomResult<serde_json::Value, errors::ConnectorError> {
+        Err(errors::ConnectorError::WebhooksNotImplemented).into_report()
+    }
+}
+
+impl services::ConnectorRedirectResponse for Worldpay {
+    fn get_flow_type(
+        &self,
+        _query_params: &str,
+    ) -> CustomResult<payments::CallConnectorAction, errors::ConnectorError> {
+        Ok(payments::CallConnectorAction::Trigger)
+    }
+}
diff --git a/crates/router/src/connector/worldpay/requests.rs b/crates/router/src/connector/worldpay/requests.rs
new file mode 100644
index 00000000000..a76b02d7cfd
--- /dev/null
+++ b/crates/router/src/connector/worldpay/requests.rs
@@ -0,0 +1,225 @@
+use serde::{Deserialize, Serialize};
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct BillingAddress {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub city: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub address2: Option<String>,
+    pub postal_code: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub state: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub address3: Option<String>,
+    pub country_code: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub address1: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct WorldpayPaymentsRequest {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub channel: Option<Channel>,
+    pub instruction: Instruction,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub customer: Option<Customer>,
+    pub merchant: Merchant,
+    pub transaction_reference: String,
+}
+
+#[derive(
+    Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize,
+)]
+#[serde(rename_all = "camelCase")]
+pub enum Channel {
+    #[default]
+    Moto,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Customer {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub risk_profile: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub authentication: Option<CustomerAuthentication>,
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub enum CustomerAuthentication {
+    ThreeDS(ThreeDS),
+    Token(NetworkToken),
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct ThreeDS {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub authentication_value: Option<String>,
+    pub version: ThreeDSVersion,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub transaction_id: Option<String>,
+    pub eci: String,
+    #[serde(rename = "type")]
+    pub auth_type: CustomerAuthType,
+}
+
+#[derive(
+    Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize,
+)]
+pub enum ThreeDSVersion {
+    #[default]
+    #[serde(rename = "1")]
+    One,
+    #[serde(rename = "2")]
+    Two,
+}
+
+#[derive(
+    Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize,
+)]
+pub enum CustomerAuthType {
+    #[serde(rename = "3DS")]
+    #[default]
+    Variant3Ds,
+    #[serde(rename = "card/networkToken")]
+    NetworkToken,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct NetworkToken {
+    #[serde(rename = "type")]
+    pub auth_type: CustomerAuthType,
+    pub authentication_value: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub eci: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Instruction {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub debt_repayment: Option<bool>,
+    pub value: PaymentValue,
+    pub narrative: InstructionNarrative,
+    pub payment_instrument: PaymentInstrument,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct InstructionNarrative {
+    pub line1: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub line2: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[serde(untagged)]
+pub enum PaymentInstrument {
+    Card(CardPayment),
+    CardToken(CardToken),
+    Googlepay(WalletPayment),
+    Applepay(WalletPayment),
+}
+
+#[derive(
+    Clone, Copy, Debug, Eq, Default, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize,
+)]
+pub enum PaymentType {
+    #[default]
+    #[serde(rename = "card/plain")]
+    Card,
+    #[serde(rename = "card/token")]
+    CardToken,
+    #[serde(rename = "card/wallet+googlepay")]
+    Googlepay,
+    #[serde(rename = "card/wallet+applepay")]
+    Applepay,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CardPayment {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub billing_address: Option<BillingAddress>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub card_holder_name: Option<String>,
+    pub card_expiry_date: CardExpiryDate,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub cvc: Option<String>,
+    #[serde(rename = "type")]
+    pub payment_type: PaymentType,
+    pub card_number: String,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct CardToken {
+    #[serde(rename = "type")]
+    pub payment_type: PaymentType,
+    pub href: String,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct WalletPayment {
+    #[serde(rename = "type")]
+    pub payment_type: PaymentType,
+    pub wallet_token: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub billing_address: Option<BillingAddress>,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+pub struct CardExpiryDate {
+    pub month: u8,
+    pub year: u16,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+pub struct PaymentValue {
+    pub amount: i64,
+    pub currency: String,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Merchant {
+    pub entity: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub mcc: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub payment_facilitator: Option<PaymentFacilitator>,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct PaymentFacilitator {
+    pub pf_id: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub iso_id: Option<String>,
+    pub sub_merchant: SubMerchant,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct SubMerchant {
+    pub city: String,
+    pub name: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub state: Option<String>,
+    pub postal_code: String,
+    pub merchant_id: String,
+    pub country_code: String,
+    pub street: String,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub tax_id: Option<String>,
+}
+
+#[derive(Default, Debug, Serialize)]
+pub struct WorldpayRefundRequest {
+    pub value: PaymentValue,
+    pub reference: String,
+}
diff --git a/crates/router/src/connector/worldpay/response.rs b/crates/router/src/connector/worldpay/response.rs
new file mode 100644
index 00000000000..5102ac9528c
--- /dev/null
+++ b/crates/router/src/connector/worldpay/response.rs
@@ -0,0 +1,306 @@
+use serde::{Deserialize, Serialize};
+
+use crate::{core::errors, types};
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct WorldpayPaymentsResponse {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub exemption: Option<Exemption>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub issuer: Option<Issuer>,
+    pub outcome: Option<Outcome>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub description: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub payment_instrument: Option<PaymentsResPaymentInstrument>,
+    /// Any risk factors which have been identified for the authorization. This section will not appear if no risks are identified.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub risk_factors: Option<Vec<RiskFactorsInner>>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub scheme: Option<PaymentsResponseScheme>,
+    #[serde(rename = "_links", skip_serializing_if = "Option::is_none")]
+    pub links: Option<PaymentLinks>,
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub enum Outcome {
+    Authorized,
+    Refused,
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct WorldpayEventResponse {
+    pub last_event: EventType,
+    #[serde(rename = "_links", skip_serializing_if = "Option::is_none")]
+    pub links: Option<EventLinks>,
+}
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub enum EventType {
+    Authorized,
+    Cancelled,
+    Charged,
+    SentForRefund,
+    RefundFailed,
+    Refused,
+    Refunded,
+    Error,
+    CaptureFailed,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+pub struct Exemption {
+    pub result: String,
+    pub reason: String,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+pub struct PaymentLinks {
+    #[serde(rename = "payments:events", skip_serializing_if = "Option::is_none")]
+    pub events: Option<PaymentLink>,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+pub struct EventLinks {
+    #[serde(rename = "payments:events", skip_serializing_if = "Option::is_none")]
+    pub events: Option<String>,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+pub struct PaymentLink {
+    pub href: String,
+}
+
+fn get_resource_id<T, F>(
+    links: Option<PaymentLinks>,
+    transform_fn: F,
+) -> Result<T, error_stack::Report<errors::ConnectorError>>
+where
+    F: Fn(String) -> T,
+{
+    let reference_id = links
+        .and_then(|l| l.events)
+        .and_then(|e| e.href.rsplit_once('/').map(|h| h.1.to_string()))
+        .map(transform_fn);
+    reference_id.ok_or_else(|| {
+        errors::ConnectorError::MissingRequiredField {
+            field_name: "links.events".to_string(),
+        }
+        .into()
+    })
+}
+
+pub struct ResponseIdStr {
+    pub id: String,
+}
+
+impl TryFrom<Option<PaymentLinks>> for ResponseIdStr {
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(links: Option<PaymentLinks>) -> Result<Self, Self::Error> {
+        get_resource_id(links, |id| Self { id })
+    }
+}
+
+impl TryFrom<Option<PaymentLinks>> for types::ResponseId {
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(links: Option<PaymentLinks>) -> Result<Self, Self::Error> {
+        get_resource_id(links, Self::ConnectorTransactionId)
+    }
+}
+
+impl Exemption {
+    pub fn new(result: String, reason: String) -> Self {
+        Self { result, reason }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Issuer {
+    pub authorization_code: String,
+}
+
+impl Issuer {
+    pub fn new(authorization_code: String) -> Self {
+        Self { authorization_code }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+pub struct PaymentsResPaymentInstrument {
+    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
+    pub risk_type: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub card: Option<PaymentInstrumentCard>,
+}
+
+impl PaymentsResPaymentInstrument {
+    pub fn new() -> Self {
+        Self {
+            risk_type: None,
+            card: None,
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct PaymentInstrumentCard {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub number: Option<PaymentInstrumentCardNumber>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub issuer: Option<PaymentInstrumentCardIssuer>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub payment_account_reference: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub country_code: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub funding_type: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub brand: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub expiry_date: Option<PaymentInstrumentCardExpiryDate>,
+}
+
+impl PaymentInstrumentCard {
+    pub fn new() -> Self {
+        Self {
+            number: None,
+            issuer: None,
+            payment_account_reference: None,
+            country_code: None,
+            funding_type: None,
+            brand: None,
+            expiry_date: None,
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct PaymentInstrumentCardExpiryDate {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub month: Option<i32>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub year: Option<i32>,
+}
+
+impl PaymentInstrumentCardExpiryDate {
+    pub fn new() -> Self {
+        Self {
+            month: None,
+            year: None,
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct PaymentInstrumentCardIssuer {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub name: Option<String>,
+}
+
+impl PaymentInstrumentCardIssuer {
+    pub fn new() -> Self {
+        Self { name: None }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct PaymentInstrumentCardNumber {
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub bin: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub last4_digits: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub dpan: Option<String>,
+}
+
+impl PaymentInstrumentCardNumber {
+    pub fn new() -> Self {
+        Self {
+            bin: None,
+            last4_digits: None,
+            dpan: None,
+        }
+    }
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[serde(rename_all = "camelCase")]
+pub struct RiskFactorsInner {
+    #[serde(rename = "type")]
+    pub risk_type: RiskType,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub detail: Option<Detail>,
+    pub risk: Risk,
+}
+
+impl RiskFactorsInner {
+    pub fn new(risk_type: RiskType, risk: Risk) -> Self {
+        Self {
+            risk_type,
+            detail: None,
+            risk,
+        }
+    }
+}
+
+#[derive(
+    Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize,
+)]
+#[serde(rename_all = "camelCase")]
+pub enum RiskType {
+    #[default]
+    Avs,
+    Cvc,
+    RiskProfile,
+}
+
+#[derive(
+    Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize,
+)]
+#[serde(rename_all = "camelCase")]
+pub enum Detail {
+    #[default]
+    Address,
+    Postcode,
+}
+
+#[derive(
+    Clone, Copy, Default, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize,
+)]
+pub enum Risk {
+    #[default]
+    #[serde(rename = "not_checked")]
+    NotChecked,
+    #[serde(rename = "not_matched")]
+    NotMatched,
+    #[serde(rename = "not_supplied")]
+    NotSupplied,
+    #[serde(rename = "verificationFailed")]
+    VerificationFailed,
+}
+
+#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+pub struct PaymentsResponseScheme {
+    pub reference: String,
+}
+
+impl PaymentsResponseScheme {
+    pub fn new(reference: String) -> Self {
+        Self { reference }
+    }
+}
+
+#[derive(Default, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "camelCase")]
+pub struct WorldpayErrorResponse {
+    pub error_name: String,
+    pub message: String,
+}
diff --git a/crates/router/src/connector/worldpay/transformers.rs b/crates/router/src/connector/worldpay/transformers.rs
new file mode 100644
index 00000000000..0ca5da3c780
--- /dev/null
+++ b/crates/router/src/connector/worldpay/transformers.rs
@@ -0,0 +1,179 @@
+use std::str::FromStr;
+
+use common_utils::errors::CustomResult;
+use masking::PeekInterface;
+use storage_models::enums;
+
+use super::{requests::*, response::*};
+use crate::{
+    core::errors,
+    types::{self, api},
+};
+
+fn parse_int<T: FromStr>(
+    val: masking::Secret<String, masking::WithType>,
+) -> CustomResult<T, errors::ConnectorError>
+where
+    <T as FromStr>::Err: Sync,
+{
+    let res = val.peek().parse::<T>();
+    if let Ok(val) = res {
+        Ok(val)
+    } else {
+        Err(errors::ConnectorError::RequestEncodingFailed)?
+    }
+}
+
+fn fetch_payment_instrument(
+    payment_method: api::PaymentMethod,
+) -> CustomResult<PaymentInstrument, errors::ConnectorError> {
+    match payment_method {
+        api::PaymentMethod::Card(card) => Ok(PaymentInstrument::Card(CardPayment {
+            card_expiry_date: CardExpiryDate {
+                month: parse_int::<u8>(card.card_exp_month)?,
+                year: parse_int::<u16>(card.card_exp_year)?,
+            },
+            card_number: card.card_number.peek().to_string(),
+            ..CardPayment::default()
+        })),
+        api::PaymentMethod::Wallet(wallet) => match wallet.issuer_name {
+            api_models::enums::WalletIssuer::ApplePay => {
+                Ok(PaymentInstrument::Applepay(WalletPayment {
+                    payment_type: PaymentType::Applepay,
+                    wallet_token: wallet.token,
+                    ..WalletPayment::default()
+                }))
+            }
+            api_models::enums::WalletIssuer::GooglePay => {
+                Ok(PaymentInstrument::Googlepay(WalletPayment {
+                    payment_type: PaymentType::Googlepay,
+                    wallet_token: wallet.token,
+                    ..WalletPayment::default()
+                }))
+            }
+            _ => Err(errors::ConnectorError::NotImplemented("Wallet Type".to_string()).into()),
+        },
+        _ => {
+            Err(errors::ConnectorError::NotImplemented("Current Payment Method".to_string()).into())
+        }
+    }
+}
+
+impl TryFrom<&types::PaymentsAuthorizeRouterData> for WorldpayPaymentsRequest {
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result<Self, Self::Error> {
+        Ok(Self {
+            instruction: Instruction {
+                value: PaymentValue {
+                    amount: item.request.amount,
+                    currency: item.request.currency.to_string(),
+                },
+                narrative: InstructionNarrative {
+                    line1: item.merchant_id.clone(),
+                    ..Default::default()
+                },
+                payment_instrument: fetch_payment_instrument(
+                    item.request.payment_method_data.clone(),
+                )?,
+                debt_repayment: None,
+            },
+            merchant: Merchant {
+                entity: item.payment_id.clone(),
+                ..Default::default()
+            },
+            transaction_reference: item.attempt_id.clone().ok_or(
+                errors::ConnectorError::MissingRequiredField {
+                    field_name: "attempt_id".to_string(),
+                },
+            )?,
+            channel: None,
+            customer: None,
+        })
+    }
+}
+
+pub struct WorldpayAuthType {
+    pub(super) api_key: String,
+}
+
+impl TryFrom<&types::ConnectorAuthType> for WorldpayAuthType {
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(auth_type: &types::ConnectorAuthType) -> Result<Self, Self::Error> {
+        match auth_type {
+            types::ConnectorAuthType::HeaderKey { api_key } => Ok(Self {
+                api_key: api_key.to_string(),
+            }),
+            _ => Err(errors::ConnectorError::FailedToObtainAuthType)?,
+        }
+    }
+}
+
+impl From<Outcome> for enums::AttemptStatus {
+    fn from(item: Outcome) -> Self {
+        match item {
+            Outcome::Authorized => Self::Authorized,
+            Outcome::Refused => Self::Failure,
+        }
+    }
+}
+
+impl From<EventType> for enums::AttemptStatus {
+    fn from(value: EventType) -> Self {
+        match value {
+            EventType::Authorized => Self::Authorized,
+            EventType::CaptureFailed => Self::CaptureFailed,
+            EventType::Refused => Self::Failure,
+            EventType::Charged => Self::Charged,
+            _ => Self::Pending,
+        }
+    }
+}
+
+impl From<EventType> for enums::RefundStatus {
+    fn from(value: EventType) -> Self {
+        match value {
+            EventType::Refunded => Self::Success,
+            EventType::RefundFailed => Self::Failure,
+            _ => Self::Pending,
+        }
+    }
+}
+
+impl TryFrom<types::PaymentsResponseRouterData<WorldpayPaymentsResponse>>
+    for types::PaymentsAuthorizeRouterData
+{
+    type Error = error_stack::Report<errors::ConnectorError>;
+    fn try_from(
+        item: types::PaymentsResponseRouterData<WorldpayPaymentsResponse>,
+    ) -> Result<Self, Self::Error> {
+        Ok(Self {
+            status: match item.response.outcome {
+                Some(outcome) => enums::AttemptStatus::from(outcome),
+                None => Err(errors::ConnectorError::MissingRequiredField {
+                    field_name: "outcome".to_string(),
+                })?,
+            },
+            description: item.response.description,
+            response: Ok(types::PaymentsResponseData::TransactionResponse {
+                resource_id: types::ResponseId::try_from(item.response.links)?,
+                redirection_data: None,
+                redirect: false,
+                mandate_reference: None,
+            }),
+            ..item.data
+        })
+    }
+}
+
+impl<F> TryFrom<&types::RefundsRouterData<F>> for WorldpayRefundRequest {
+    type Error = error_stack::Report<errors::ParsingError>;
+    fn try_from(item: &types::RefundsRouterData<F>) -> Result<Self, Self::Error> {
+        Ok(Self {
+            reference: item.request.connector_transaction_id.clone(),
+            value: PaymentValue {
+                amount: item.request.amount,
+                currency: item.request.currency.to_string(),
+            },
+        })
+    }
+}
diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs
index e09e2ffd663..fa9688f4de0 100644
--- a/crates/router/src/core/errors.rs
+++ b/crates/router/src/core/errors.rs
@@ -241,8 +241,8 @@ pub enum ApiClientError {
 
     #[error("URL encoding of request payload failed")]
     UrlEncodingFailed,
-    #[error("Failed to send request to connector")]
-    RequestNotSent,
+    #[error("Failed to send request to connector {0}")]
+    RequestNotSent(String),
     #[error("Failed to decode response")]
     ResponseDecodingFailed,
 
diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs
index da71234f4c6..0fa67b6eeed 100644
--- a/crates/router/src/core/payments/transformers.rs
+++ b/crates/router/src/core/payments/transformers.rs
@@ -79,6 +79,7 @@ where
         merchant_id: merchant_account.merchant_id.clone(),
         connector: merchant_connector_account.connector_name,
         payment_id: payment_data.payment_attempt.payment_id.clone(),
+        attempt_id: Some(payment_data.payment_attempt.attempt_id.clone()),
         status: payment_data.payment_attempt.status,
         payment_method,
         connector_auth_type: auth_type,
diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs
index 9a721910176..fa7f831bad1 100644
--- a/crates/router/src/core/utils.rs
+++ b/crates/router/src/core/utils.rs
@@ -66,6 +66,7 @@ pub async fn construct_refund_router_data<'a, F>(
         merchant_id: merchant_account.merchant_id.clone(),
         connector: merchant_connector_account.connector_name,
         payment_id: payment_attempt.payment_id.clone(),
+        attempt_id: Some(payment_attempt.attempt_id.clone()),
         status,
         payment_method: payment_method_type,
         connector_auth_type: auth_type,
diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs
index fb4e61bf14e..5306dd65003 100644
--- a/crates/router/src/services/api.rs
+++ b/crates/router/src/services/api.rs
@@ -248,7 +248,7 @@ async fn send_request(
     }
     .map_err(|error| match error {
         error if error.is_timeout() => errors::ApiClientError::RequestTimeoutReceived,
-        _ => errors::ApiClientError::RequestNotSent,
+        _ => errors::ApiClientError::RequestNotSent(error.to_string()),
     })
     .into_report()
     .attach_printable("Unable to send request to connector")
diff --git a/crates/router/src/types.rs b/crates/router/src/types.rs
index 4e0837ec98a..2492fe6b16f 100644
--- a/crates/router/src/types.rs
+++ b/crates/router/src/types.rs
@@ -69,6 +69,7 @@ pub struct RouterData<Flow, Request, Response> {
     pub merchant_id: String,
     pub connector: String,
     pub payment_id: String,
+    pub attempt_id: Option<String>,
     pub status: storage_enums::AttemptStatus,
     pub payment_method: storage_enums::PaymentMethodType,
     pub connector_auth_type: ConnectorAuthType,
diff --git a/crates/router/src/types/api.rs b/crates/router/src/types/api.rs
index fb037b1a212..1ecc0c793b5 100644
--- a/crates/router/src/types/api.rs
+++ b/crates/router/src/types/api.rs
@@ -149,6 +149,7 @@ impl ConnectorData {
             "applepay" => Ok(Box::new(&connector::Applepay)),
             "cybersource" => Ok(Box::new(&connector::Cybersource)),
             "shift4" => Ok(Box::new(&connector::Shift4)),
+            "worldpay" => Ok(Box::new(&connector::Worldpay)),
             _ => Err(report!(errors::UnexpectedError)
                 .attach_printable(format!("invalid connector name: {connector_name}")))
             .change_context(errors::ConnectorError::InvalidConnectorName)
diff --git a/crates/router/tests/connectors/aci.rs b/crates/router/tests/connectors/aci.rs
index f56cdec15b8..170e86d6643 100644
--- a/crates/router/tests/connectors/aci.rs
+++ b/crates/router/tests/connectors/aci.rs
@@ -22,6 +22,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
         merchant_id: String::from("aci"),
         connector: "aci".to_string(),
         payment_id: uuid::Uuid::new_v4().to_string(),
+        attempt_id: None,
         status: enums::AttemptStatus::default(),
         auth_type: enums::AuthenticationType::NoThreeDs,
         payment_method: enums::PaymentMethodType::Card,
@@ -68,6 +69,7 @@ fn construct_refund_router_data<F>() -> types::RefundsRouterData<F> {
         merchant_id: String::from("aci"),
         connector: "aci".to_string(),
         payment_id: uuid::Uuid::new_v4().to_string(),
+        attempt_id: None,
         status: enums::AttemptStatus::default(),
         router_return_url: None,
         payment_method: enums::PaymentMethodType::Card,
diff --git a/crates/router/tests/connectors/authorizedotnet.rs b/crates/router/tests/connectors/authorizedotnet.rs
index 5225f155477..b8bd87e325d 100644
--- a/crates/router/tests/connectors/authorizedotnet.rs
+++ b/crates/router/tests/connectors/authorizedotnet.rs
@@ -22,6 +22,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
         merchant_id: String::from("authorizedotnet"),
         connector: "authorizedotnet".to_string(),
         payment_id: uuid::Uuid::new_v4().to_string(),
+        attempt_id: None,
         status: enums::AttemptStatus::default(),
         router_return_url: None,
         payment_method: enums::PaymentMethodType::Card,
@@ -69,6 +70,7 @@ fn construct_refund_router_data<F>() -> types::RefundsRouterData<F> {
         merchant_id: String::from("authorizedotnet"),
         connector: "authorizedotnet".to_string(),
         payment_id: uuid::Uuid::new_v4().to_string(),
+        attempt_id: None,
         status: enums::AttemptStatus::default(),
         router_return_url: None,
         auth_type: enums::AuthenticationType::NoThreeDs,
diff --git a/crates/router/tests/connectors/checkout.rs b/crates/router/tests/connectors/checkout.rs
index 0038b357e62..7e3adddf155 100644
--- a/crates/router/tests/connectors/checkout.rs
+++ b/crates/router/tests/connectors/checkout.rs
@@ -19,6 +19,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
         merchant_id: "checkout".to_string(),
         connector: "checkout".to_string(),
         payment_id: uuid::Uuid::new_v4().to_string(),
+        attempt_id: None,
         status: enums::AttemptStatus::default(),
         router_return_url: None,
         auth_type: enums::AuthenticationType::NoThreeDs,
@@ -66,6 +67,7 @@ fn construct_refund_router_data<F>() -> types::RefundsRouterData<F> {
         merchant_id: "checkout".to_string(),
         connector: "checkout".to_string(),
         payment_id: uuid::Uuid::new_v4().to_string(),
+        attempt_id: None,
         status: enums::AttemptStatus::default(),
         router_return_url: None,
         payment_method: enums::PaymentMethodType::Card,
diff --git a/crates/router/tests/connectors/connector_auth.rs b/crates/router/tests/connectors/connector_auth.rs
index 5be73e5aaaa..decacf4d6b3 100644
--- a/crates/router/tests/connectors/connector_auth.rs
+++ b/crates/router/tests/connectors/connector_auth.rs
@@ -7,6 +7,7 @@ pub(crate) struct ConnectorAuthentication {
     pub authorizedotnet: Option<BodyKey>,
     pub checkout: Option<BodyKey>,
     pub shift4: Option<HeaderKey>,
+    pub worldpay: Option<HeaderKey>,
 }
 
 impl ConnectorAuthentication {
diff --git a/crates/router/tests/connectors/main.rs b/crates/router/tests/connectors/main.rs
index b4ea15522d8..3f74d71ed34 100644
--- a/crates/router/tests/connectors/main.rs
+++ b/crates/router/tests/connectors/main.rs
@@ -6,3 +6,4 @@ mod checkout;
 mod connector_auth;
 mod shift4;
 mod utils;
+mod worldpay;
diff --git a/crates/router/tests/connectors/sample_auth.toml b/crates/router/tests/connectors/sample_auth.toml
index 23b7a383ab5..eedea2a0ad2 100644
--- a/crates/router/tests/connectors/sample_auth.toml
+++ b/crates/router/tests/connectors/sample_auth.toml
@@ -14,4 +14,7 @@ api_key = "Bearer MyApiKey"
 key1 = "MyProcessingChannelId"
 
 [shift4]
+api_key = "Bearer MyApiKey"
+
+[worldpay]
 api_key = "Bearer MyApiKey"
\ No newline at end of file
diff --git a/crates/router/tests/connectors/utils.rs b/crates/router/tests/connectors/utils.rs
index b5f55f4e87c..5ae3ccb8865 100644
--- a/crates/router/tests/connectors/utils.rs
+++ b/crates/router/tests/connectors/utils.rs
@@ -8,6 +8,7 @@ use router::{
     routes, services,
     types::{self, api, storage::enums, PaymentAddress},
 };
+use wiremock::{Mock, MockServer};
 
 pub trait Connector {
     fn get_data(&self) -> types::api::ConnectorData;
@@ -25,6 +26,7 @@ pub trait ConnectorActions: Connector {
         let request = generate_data(
             self.get_name(),
             self.get_auth_token(),
+            enums::AuthenticationType::NoThreeDs,
             payment_data.unwrap_or_else(|| types::PaymentsAuthorizeData {
                 capture_method: Some(storage_models::enums::CaptureMethod::Manual),
                 ..PaymentAuthorizeType::default().0
@@ -40,10 +42,26 @@ pub trait ConnectorActions: Connector {
         let request = generate_data(
             self.get_name(),
             self.get_auth_token(),
+            enums::AuthenticationType::NoThreeDs,
             payment_data.unwrap_or_else(|| PaymentAuthorizeType::default().0),
         );
         call_connector(request, integration).await
     }
+
+    async fn sync_payment(
+        &self,
+        payment_data: Option<types::PaymentsSyncData>,
+    ) -> types::PaymentsSyncRouterData {
+        let integration = self.get_data().connector.get_connector_integration();
+        let request = generate_data(
+            self.get_name(),
+            self.get_auth_token(),
+            enums::AuthenticationType::NoThreeDs,
+            payment_data.unwrap_or_else(|| PaymentSyncType::default().0),
+        );
+        call_connector(request, integration).await
+    }
+
     async fn capture_payment(
         &self,
         transaction_id: String,
@@ -53,6 +71,7 @@ pub trait ConnectorActions: Connector {
         let request = generate_data(
             self.get_name(),
             self.get_auth_token(),
+            enums::AuthenticationType::NoThreeDs,
             payment_data.unwrap_or(types::PaymentsCaptureData {
                 amount_to_capture: Some(100),
                 connector_transaction_id: transaction_id,
@@ -62,6 +81,25 @@ pub trait ConnectorActions: Connector {
         );
         call_connector(request, integration).await
     }
+
+    async fn void_payment(
+        &self,
+        transaction_id: String,
+        payment_data: Option<types::PaymentsCancelData>,
+    ) -> types::PaymentsCancelRouterData {
+        let integration = self.get_data().connector.get_connector_integration();
+        let request = generate_data(
+            self.get_name(),
+            self.get_auth_token(),
+            enums::AuthenticationType::NoThreeDs,
+            payment_data.unwrap_or(types::PaymentsCancelData {
+                connector_transaction_id: transaction_id,
+                cancellation_reason: Some("Test cancellation".to_string()),
+            }),
+        );
+        call_connector(request, integration).await
+    }
+
     async fn refund_payment(
         &self,
         transaction_id: String,
@@ -71,6 +109,29 @@ pub trait ConnectorActions: Connector {
         let request = generate_data(
             self.get_name(),
             self.get_auth_token(),
+            enums::AuthenticationType::NoThreeDs,
+            payment_data.unwrap_or_else(|| types::RefundsData {
+                amount: 100,
+                currency: enums::Currency::USD,
+                refund_id: uuid::Uuid::new_v4().to_string(),
+                payment_method_data: types::api::PaymentMethod::Card(CCardType::default().0),
+                connector_transaction_id: transaction_id,
+                refund_amount: 100,
+            }),
+        );
+        call_connector(request, integration).await
+    }
+
+    async fn sync_refund(
+        &self,
+        transaction_id: String,
+        payment_data: Option<types::RefundsData>,
+    ) -> types::RefundSyncRouterData {
+        let integration = self.get_data().connector.get_connector_integration();
+        let request = generate_data(
+            self.get_name(),
+            self.get_auth_token(),
+            enums::AuthenticationType::NoThreeDs,
             payment_data.unwrap_or_else(|| types::RefundsData {
                 amount: 100,
                 currency: enums::Currency::USD,
@@ -105,7 +166,32 @@ async fn call_connector<
     .unwrap()
 }
 
+pub struct MockConfig {
+    pub address: Option<String>,
+    pub mocks: Vec<Mock>,
+}
+
+#[async_trait]
+pub trait LocalMock {
+    async fn start_server(&self, config: MockConfig) -> MockServer {
+        let address = config
+            .address
+            .unwrap_or_else(|| "127.0.0.1:9090".to_string());
+        let listener = std::net::TcpListener::bind(address).unwrap();
+        let expected_server_address = listener
+            .local_addr()
+            .expect("Failed to get server address.");
+        let mock_server = MockServer::builder().listener(listener).start().await;
+        assert_eq!(&expected_server_address, mock_server.address());
+        for mock in config.mocks {
+            mock_server.register(mock).await;
+        }
+        mock_server
+    }
+}
+
 pub struct PaymentAuthorizeType(pub types::PaymentsAuthorizeData);
+pub struct PaymentSyncType(pub types::PaymentsSyncData);
 pub struct PaymentRefundType(pub types::RefundsData);
 pub struct CCardType(pub api::CCard);
 
@@ -142,6 +228,18 @@ impl Default for PaymentAuthorizeType {
     }
 }
 
+impl Default for PaymentSyncType {
+    fn default() -> Self {
+        let data = types::PaymentsSyncData {
+            connector_transaction_id: types::ResponseId::ConnectorTransactionId(
+                "12345".to_string(),
+            ),
+            encoded_data: None,
+        };
+        Self(data)
+    }
+}
+
 impl Default for PaymentRefundType {
     fn default() -> Self {
         let data = types::RefundsData {
@@ -171,6 +269,7 @@ pub fn get_connector_transaction_id(
 fn generate_data<Flow, Req: From<Req>, Res>(
     connector: String,
     connector_auth_type: types::ConnectorAuthType,
+    auth_type: enums::AuthenticationType,
     req: Req,
 ) -> types::RouterData<Flow, Req, Res> {
     types::RouterData {
@@ -178,9 +277,10 @@ fn generate_data<Flow, Req: From<Req>, Res>(
         merchant_id: connector.clone(),
         connector,
         payment_id: uuid::Uuid::new_v4().to_string(),
+        attempt_id: Some(uuid::Uuid::new_v4().to_string()),
         status: enums::AttemptStatus::default(),
         router_return_url: None,
-        auth_type: enums::AuthenticationType::NoThreeDs,
+        auth_type,
         payment_method: enums::PaymentMethodType::Card,
         connector_auth_type,
         description: Some("This is a test".to_string()),
diff --git a/crates/router/tests/connectors/worldpay.rs b/crates/router/tests/connectors/worldpay.rs
new file mode 100644
index 00000000000..3a123239a11
--- /dev/null
+++ b/crates/router/tests/connectors/worldpay.rs
@@ -0,0 +1,320 @@
+use futures::future::OptionFuture;
+use router::types::{
+    self,
+    api::{self, enums as api_enums},
+    storage::enums,
+};
+use serde_json::json;
+use serial_test::serial;
+use wiremock::{
+    matchers::{body_json, method, path},
+    Mock, ResponseTemplate,
+};
+
+use crate::{
+    connector_auth,
+    utils::{self, ConnectorActions, LocalMock, MockConfig},
+};
+
+struct Worldpay;
+
+impl LocalMock for Worldpay {}
+impl ConnectorActions for Worldpay {}
+impl utils::Connector for Worldpay {
+    fn get_data(&self) -> types::api::ConnectorData {
+        use router::connector::Worldpay;
+        types::api::ConnectorData {
+            connector: Box::new(&Worldpay),
+            connector_name: types::Connector::Worldpay,
+            get_token: types::api::GetToken::Connector,
+        }
+    }
+
+    fn get_auth_token(&self) -> types::ConnectorAuthType {
+        types::ConnectorAuthType::from(
+            connector_auth::ConnectorAuthentication::new()
+                .worldpay
+                .expect("Missing connector authentication configuration"),
+        )
+    }
+
+    fn get_name(&self) -> String {
+        "worldpay".to_string()
+    }
+}
+
+#[actix_web::test]
+#[serial]
+async fn should_authorize_card_payment() {
+    let conn = Worldpay {};
+    let _mock = conn.start_server(get_mock_config()).await;
+    let response = conn.authorize_payment(None).await;
+    assert_eq!(response.status, enums::AttemptStatus::Authorized);
+    assert_eq!(
+        utils::get_connector_transaction_id(response),
+        Some("123456".to_string())
+    );
+}
+
+#[actix_web::test]
+#[serial]
+async fn should_authorize_gpay_payment() {
+    let conn = Worldpay {};
+    let _mock = conn.start_server(get_mock_config()).await;
+    let response = conn
+        .authorize_payment(Some(types::PaymentsAuthorizeData {
+            payment_method_data: types::api::PaymentMethod::Wallet(api::WalletData {
+                issuer_name: api_enums::WalletIssuer::GooglePay,
+                token: "someToken".to_string(),
+            }),
+            ..utils::PaymentAuthorizeType::default().0
+        }))
+        .await;
+    assert_eq!(response.status, enums::AttemptStatus::Authorized);
+    assert_eq!(
+        utils::get_connector_transaction_id(response),
+        Some("123456".to_string())
+    );
+}
+
+#[actix_web::test]
+#[serial]
+async fn should_authorize_applepay_payment() {
+    let conn = Worldpay {};
+    let _mock = conn.start_server(get_mock_config()).await;
+    let response = conn
+        .authorize_payment(Some(types::PaymentsAuthorizeData {
+            payment_method_data: types::api::PaymentMethod::Wallet(api::WalletData {
+                issuer_name: api_enums::WalletIssuer::ApplePay,
+                token: "someToken".to_string(),
+            }),
+            ..utils::PaymentAuthorizeType::default().0
+        }))
+        .await;
+    assert_eq!(response.status, enums::AttemptStatus::Authorized);
+    assert_eq!(
+        utils::get_connector_transaction_id(response),
+        Some("123456".to_string())
+    );
+}
+
+#[actix_web::test]
+#[serial]
+async fn should_capture_already_authorized_payment() {
+    let connector = Worldpay {};
+    let _mock = connector.start_server(get_mock_config()).await;
+    let authorize_response = connector.authorize_payment(None).await;
+    assert_eq!(authorize_response.status, enums::AttemptStatus::Authorized);
+    let txn_id = utils::get_connector_transaction_id(authorize_response);
+    let response: OptionFuture<_> = txn_id
+        .map(|transaction_id| async move {
+            connector.capture_payment(transaction_id, None).await.status
+        })
+        .into();
+    assert_eq!(response.await, Some(enums::AttemptStatus::Charged));
+}
+
+#[actix_web::test]
+#[serial]
+async fn should_sync_payment() {
+    let connector = Worldpay {};
+    let _mock = connector.start_server(get_mock_config()).await;
+    let response = connector
+        .sync_payment(Some(types::PaymentsSyncData {
+            connector_transaction_id: router::types::ResponseId::ConnectorTransactionId(
+                "112233".to_string(),
+            ),
+            encoded_data: None,
+        }))
+        .await;
+    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
+}
+
+#[actix_web::test]
+#[serial]
+async fn should_void_already_authorized_payment() {
+    let connector = Worldpay {};
+    let _mock = connector.start_server(get_mock_config()).await;
+    let authorize_response = connector.authorize_payment(None).await;
+    assert_eq!(authorize_response.status, enums::AttemptStatus::Authorized);
+    let txn_id = utils::get_connector_transaction_id(authorize_response);
+    let response: OptionFuture<_> =
+        txn_id
+            .map(|transaction_id| async move {
+                connector.void_payment(transaction_id, None).await.status
+            })
+            .into();
+    assert_eq!(response.await, Some(enums::AttemptStatus::Voided));
+}
+
+#[actix_web::test]
+#[serial]
+async fn should_fail_capture_for_invalid_payment() {
+    let connector = Worldpay {};
+    let _mock = connector.start_server(get_mock_config()).await;
+    let authorize_response = connector.authorize_payment(None).await;
+    assert_eq!(authorize_response.status, enums::AttemptStatus::Authorized);
+    let response = connector.capture_payment("12345".to_string(), None).await;
+    let err = response.response.unwrap_err();
+    assert_eq!(
+        err.message,
+        "You must provide valid transaction id to capture payment".to_string()
+    );
+    assert_eq!(err.code, "invalid-id".to_string());
+}
+
+#[actix_web::test]
+#[serial]
+async fn should_refund_succeeded_payment() {
+    let connector = Worldpay {};
+    let _mock = connector.start_server(get_mock_config()).await;
+    //make a successful payment
+    let response = connector.make_payment(None).await;
+
+    //try refund for previous payment
+    let transaction_id = utils::get_connector_transaction_id(response).unwrap();
+    let response = connector.refund_payment(transaction_id, None).await;
+    assert_eq!(
+        response.response.unwrap().refund_status,
+        enums::RefundStatus::Success,
+    );
+}
+
+#[actix_web::test]
+#[serial]
+async fn should_sync_refund() {
+    let connector = Worldpay {};
+    let _mock = connector.start_server(get_mock_config()).await;
+    let response = connector.sync_refund("654321".to_string(), None).await;
+    assert_eq!(
+        response.response.unwrap().refund_status,
+        enums::RefundStatus::Success,
+    );
+}
+
+fn get_mock_config() -> MockConfig {
+    let authorized = json!({
+        "outcome": "authorized",
+        "_links": {
+            "payments:cancel": {
+                "href": "/payments/authorizations/cancellations/123456"
+            },
+            "payments:settle": {
+                "href": "/payments/settlements/123456"
+            },
+            "payments:partialSettle": {
+                "href": "/payments/settlements/partials/123456"
+            },
+            "payments:events": {
+                "href": "/payments/events/123456"
+            },
+            "curies": [
+                {
+                    "name": "payments",
+                    "href": "/rels/payments/{rel}",
+                    "templated": true
+                }
+            ]
+        }
+    });
+    let settled = json!({
+        "_links": {
+            "payments:refund": {
+                "href": "/payments/settlements/refunds/full/654321"
+            },
+            "payments:partialRefund": {
+                "href": "/payments/settlements/refunds/partials/654321"
+            },
+            "payments:events": {
+                "href": "/payments/events/654321"
+            },
+            "curies": [
+                {
+                    "name": "payments",
+                    "href": "/rels/payments/{rel}",
+                    "templated": true
+                }
+            ]
+        }
+    });
+    let error_resp = json!({
+        "errorName": "invalid-id",
+        "message": "You must provide valid transaction id to capture payment"
+    });
+    let partial_refund = json!({
+        "_links": {
+            "payments:events": {
+                "href": "https://try.access.worldpay.com/payments/events/eyJrIjoiazNhYjYzMiJ9"
+            },
+            "curies": [{
+                "name": "payments",
+                "href": "https://try.access.worldpay.com/rels/payments/{rel}",
+                "templated": true
+            }]
+        }
+    });
+    let partial_refund_req_body = json!({
+        "value": {
+            "amount": 100,
+            "currency": "USD"
+        },
+        "reference": "123456"
+    });
+    let refunded = json!({
+        "lastEvent": "refunded",
+        "_links": {
+            "payments:cancel": "/payments/authorizations/cancellations/654321",
+            "payments:settle": "/payments/settlements/full/654321",
+            "payments:partialSettle": "/payments/settlements/partials/654321",
+            "curies": [
+                {
+                    "name": "payments",
+                    "href": "/rels/payments/{rel}",
+                    "templated": true
+                }
+            ]
+        }
+    });
+    let sync_payment = json!({
+        "lastEvent": "authorized",
+        "_links": {
+            "payments:events": "/payments/authorizations/events/654321",
+            "payments:settle": "/payments/settlements/full/654321",
+            "payments:partialSettle": "/payments/settlements/partials/654321",
+            "curies": [
+                {
+                    "name": "payments",
+                    "href": "/rels/payments/{rel}",
+                    "templated": true
+                }
+            ]
+        }
+    });
+
+    MockConfig {
+        address: Some("127.0.0.1:9090".to_string()),
+        mocks: vec![
+            Mock::given(method("POST"))
+                .and(path("/payments/authorizations".to_string()))
+                .respond_with(ResponseTemplate::new(201).set_body_json(authorized)),
+            Mock::given(method("POST"))
+                .and(path("/payments/settlements/123456".to_string()))
+                .respond_with(ResponseTemplate::new(202).set_body_json(settled)),
+            Mock::given(method("GET"))
+                .and(path("/payments/events/112233".to_string()))
+                .respond_with(ResponseTemplate::new(200).set_body_json(sync_payment)),
+            Mock::given(method("POST"))
+                .and(path("/payments/settlements/12345".to_string()))
+                .respond_with(ResponseTemplate::new(400).set_body_json(error_resp)),
+            Mock::given(method("POST"))
+                .and(path(
+                    "/payments/settlements/refunds/partials/123456".to_string(),
+                ))
+                .and(body_json(partial_refund_req_body))
+                .respond_with(ResponseTemplate::new(202).set_body_json(partial_refund)),
+            Mock::given(method("GET"))
+                .and(path("/payments/events/654321".to_string()))
+                .respond_with(ResponseTemplate::new(200).set_body_json(refunded)),
+        ],
+    }
+}
diff --git a/scripts/add_connector.sh b/scripts/add_connector.sh
index 31d02d185d1..1bd23546b39 100644
--- a/scripts/add_connector.sh
+++ b/scripts/add_connector.sh
@@ -2,23 +2,43 @@ pg=$1;
 pgc="$(tr '[:lower:]' '[:upper:]' <<< ${pg:0:1})${pg:1}"
 src="crates/router/src"
 conn="$src/connector"
+tests="../../tests/connectors/"
 SCRIPT="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
 if [[ -z "$pg" ]]; then 
     echo 'Connector name not present: try "sh add_connector.sh <adyen>"'
     exit
 fi
 cd $SCRIPT/..
+# remove template files if already created for this connector
 rm -rf $conn/$pg $conn/$pg.rs
-git checkout $conn.rs $src/types/api.rs $src/configs/settings.rs
+git checkout $conn.rs $src/types/api.rs $src/configs/settings.rs config/Development.toml config/docker_compose.toml crates/api_models/src/enums.rs
+# add enum for this connector in required places
 sed -i'' -e "s/pub use self::{/pub mod ${pg};\n\npub use self::{/" $conn.rs
 sed -i'' -e "s/};/${pg}::${pgc},\n};/" $conn.rs 
 sed -i'' -e "s/_ => Err/\"${pg}\" => Ok(Box::new(\&connector::${pgc})),\n\t\t\t_ => Err/" $src/types/api.rs
 sed -i'' -e "s/pub supported: SupportedConnectors,/pub supported: SupportedConnectors,\n\tpub ${pg}: ConnectorParams,/" $src/configs/settings.rs
-rm $conn.rs-e $src/types/api.rs-e  $src/configs/settings.rs-e
+sed -i'' -e "s/\[scheduler\]/[connectors.${pg}]\nbase_url = \"\"\n\n[scheduler]/" config/Development.toml
+sed  -r -i'' -e "s/cards = \[(.*)\]/cards = [\1, \"${pg}\"]/" config/Development.toml
+sed -i'' -e "s/\[connectors.supported\]/[connectors.${pg}]\nbase_url = ""\n\n[connectors.supported]/" config/docker_compose.toml
+sed  -r -i'' -e "s/cards = \[(.*)\]/cards = [\1, \"${pg}\"]/" config/docker_compose.toml
+sed -i'' -e "s/Dummy,/Dummy,\n\t${pgc},/" crates/api_models/src/enums.rs
+# remove temporary files created in above step
+rm $conn.rs-e $src/types/api.rs-e $src/configs/settings.rs-e config/Development.toml-e config/docker_compose.toml-e crates/api_models/src/enums.rs-e
 cd $conn/ 
+# generate template files for the connector
+cargo install cargo-generate
 cargo gen-pg $pg
+# move sub files and test files to appropiate folder
 mv $pg/mod.rs $pg.rs
-mv $pg/test.rs ../../tests/connectors/$pg.rs
-sed -i'' -e "s/mod utils;/mod ${pg};\nmod utils;/" ../../tests/connectors/main.rs
-rm ../../tests/connectors/main.rs-e
-echo "Successfully created connector: try running the tests of "$pg.rs
\ No newline at end of file
+mv $pg/test.rs ${tests}/$pg.rs
+# remove changes from tests if already done for this connector
+git checkout ${tests}/main.rs ${tests}/connector_auth.rs 
+# add enum for this connector in test folder
+sed -i'' -e "s/mod utils;/mod ${pg};\nmod utils;/" ${tests}/main.rs
+sed -i'' -e "s/struct ConnectorAuthentication {/struct ConnectorAuthentication {\n\tpub ${pg}: Option<HeaderKey>,/" ${tests}/connector_auth.rs 
+# remove temporary files created in above step
+rm ${tests}/main.rs-e ${tests}/connector_auth.rs-e 
+cargo build
+echo "Successfully created connector. Running the tests of "$pg.rs
+# runs tests for the new connector
+cargo test --package router --test connectors -- $pg
\ No newline at end of file

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [X] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates

## Description
<!-- Describe your changes in detail -->
Adding support for [worldpay](https://developer.worldpay.com/) payment gateway
Updated connector creation script and readme file

**Payment Method**: card, wallet(google, apple)
**Supported payment flows**

- [Authorize](https://developer.worldpay.com/docs/access-worldpay/api/references/payments/authorizations)
- [Capture](https://developer.worldpay.com/docs/access-worldpay/api/references/payments/authorizations/settlement)
- [PSync](https://developer.worldpay.com/docs/access-worldpay/api/references/payments/paymenteventquery)
- [Refund](https://developer.worldpay.com/docs/access-worldpay/api/references/payments/authorizations/partialsettlement/refund)
- [RSync](https://developer.worldpay.com/docs/access-worldpay/api/references/payments/paymenteventquery)
- [Cancel](https://developer.worldpay.com/docs/access-worldpay/api/references/payments/authorizations/cancellation)

### Additional Changes

- [ ] This PR modifies the database schema
- [X] This PR modifies application configuration/environment variables

<!-- 
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless its an obvious bug or documentation fix
that will have little conversation).
-->
Adding new connector [worldpay](https://developer.worldpay.com/)

## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
Added unit tests for mentioned payment flows. We currently don't have a sandbox account for Worldpay so testing is done with the help of [wiremock](https://docs.rs/wiremock/latest/wiremock/).
<img width="911" alt="Screenshot 2023-01-03 at 12 23 43 AM" src="https://user-images.githubusercontent.com/20727598/210277024-d8ae4b53-9f5e-48d3-91b0-3762882f6f11.png">


## Checklist
<!-- Put an `x` in the boxes that apply -->

- [X] I formatted the code `cargo +nightly fmt`
- [X] I addressed lints thrown by `cargo clippy`
- [X] I reviewed submitted code
- [X] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
